374 lines
18 KiB
JSON
374 lines
18 KiB
JSON
{
|
||
"name": "Dart 开发实战",
|
||
"lvNames": [
|
||
"基础语法",
|
||
"控制流与函数",
|
||
"集合",
|
||
"面向对象",
|
||
"空安全与异步",
|
||
"Dart 高级特性"
|
||
],
|
||
"questions": [
|
||
{
|
||
"lv": 1,
|
||
"q": "开发注册页时,用户输入的年龄是字符串,需要转成 <code>int</code> 保存。已知 <code>String ageText = \"18\";</code>,正确的转换写法是?",
|
||
"opts": [
|
||
"<code>ageText.parseInt()</code>",
|
||
"<code>int.parse(ageText)</code>",
|
||
"<code>int(ageText)</code>",
|
||
"<code>toInt(ageText)</code>"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<code>int.parse()</code> 把字符串解析成整数,解析失败会抛 FormatException,更稳妥的是 <code>int.tryParse()</code>(失败返回 null)。注意 Dart 没有 <code>\"18\".parseInt()</code> 这种写法,<code>int(...)</code> 也不是转换函数。"
|
||
},
|
||
{
|
||
"lv": 1,
|
||
"q": "项目里要定义一个\"永远不允许修改\"的 API 地址常量,以下哪种声明最合适?",
|
||
"opts": [
|
||
"<code>var api = \"https://api.example.com\";</code>",
|
||
"<code>final String api = \"https://api.example.com\";</code>",
|
||
"<code>String api = \"https://api.example.com\";</code>",
|
||
"<code>const String api = \"https://api.example.com\";</code>"
|
||
],
|
||
"ans": 3,
|
||
"exp": "<b>const</b> 是编译期常量:值在编译时就确定,且不可变,编译器可直接内联替换,还能配合 const 构造函数做实例复用。<b>final</b> 是运行期赋值一次后不可变。给字面量常量用 const 是更优选择。"
|
||
},
|
||
{
|
||
"lv": 1,
|
||
"q": "你在重构代码时写下:<code>var x = 10; x = \"hello\";</code> 会发生什么?",
|
||
"opts": [
|
||
"运行时报错",
|
||
"正常运行,x 变成字符串",
|
||
"编译报错:x 已被推断为 int 类型",
|
||
"x 自动变为 null"
|
||
],
|
||
"ans": 2,
|
||
"exp": "<b>var</b> 声明时由初始值自动推断类型,推断后类型就<b>固定</b>了:x 是 int,再赋 String 在编译期直接报错。想存任意类型,应显式声明 <code>dynamic</code> 或 <code>Object?</code>。"
|
||
},
|
||
{
|
||
"lv": 1,
|
||
"q": "给变量起名时,以下哪个<b>不是</b>合法的 Dart 标识符?",
|
||
"opts": [
|
||
"<code>name_2</code>",
|
||
"<code>2x</code>",
|
||
"<code>中文名</code>",
|
||
"<code>_score</code>"
|
||
],
|
||
"ans": 1,
|
||
"exp": "Dart 标识符<b>不能以数字开头</b>。<code>_score</code> 合法(下划线开头表示库内私有,是 Dart 的约定俗成);Dart 支持 Unicode 标识符,中文变量名同样合法。"
|
||
},
|
||
{
|
||
"lv": 1,
|
||
"q": "结算功能计算人均消费:<code>int total = 10; int people = 4; double avg = total / people;</code> 打印 <code>avg</code> 得到?",
|
||
"opts": [
|
||
"2.0",
|
||
"2",
|
||
"2.5",
|
||
"报错"
|
||
],
|
||
"ans": 2,
|
||
"exp": "Dart 中 <b>int 除以 int 的结果一定是 double</b>:10 / 4 = 2.5。想得到整除结果用 <code>~/</code>:<code>10 ~/ 4 == 2</code>,取余用 <code>%</code>。"
|
||
},
|
||
{
|
||
"lv": 2,
|
||
"q": "写优惠逻辑:订单数 > 10 打 9 折,> 50 打 8 折。对 <code>orders = 60</code>,以下代码会得到什么折扣?<br><code>double d; if (orders > 10) { d = 0.9; } else if (orders > 50) { d = 0.8; }</code>",
|
||
"opts": [
|
||
"0.7",
|
||
"0.8",
|
||
"1.0",
|
||
"0.9"
|
||
],
|
||
"ans": 3,
|
||
"exp": "if-else 链<b>从上到下匹配,命中即止</b>:60 > 10 先成立就直接取 0.9,后面的 else if 不再执行。正确写法应把范围大的条件放前面(先判断 > 50)。判断顺序是 if-else 链最经典的坑。"
|
||
},
|
||
{
|
||
"lv": 2,
|
||
"q": "接口返回 <code>Map<String, dynamic> data</code>,想遍历所有 key 打印出来,以下哪种写法正确?",
|
||
"opts": [
|
||
"<code>data.keys.forEach(print);</code>",
|
||
"B 和 C 都可以",
|
||
"<code>for (var k in data) print(k);</code>",
|
||
"<code>for (var k in data.keys) print(k);</code>"
|
||
],
|
||
"ans": 1,
|
||
"exp": "Map 本身<b>不能</b>直接 for-in 遍历,要先取 <code>keys</code> / <code>values</code> / <code>entries</code>。B 是标准写法;C 中 <code>forEach(print)</code> 利用了函数引用,同样正确。两种都行,按团队规范选择。"
|
||
},
|
||
{
|
||
"lv": 2,
|
||
"q": "写一个返回用户名的函数:<code>String getUserName() { }</code>,忘了写 <code>return</code>,会怎样?",
|
||
"opts": [
|
||
"运行时崩溃",
|
||
"自动返回空字符串",
|
||
"编译报错",
|
||
"返回 null"
|
||
],
|
||
"ans": 2,
|
||
"exp": "空安全下,声明了非空返回类型 <code>String</code> 的函数<b>必须有 return</b>,漏写直接编译报错,把隐患消灭在编译期。如果确实允许无返回值,应把返回类型声明为 <code>String?</code>。"
|
||
},
|
||
{
|
||
"lv": 2,
|
||
"q": "问候函数:<code>void greet(String name, {String greeting = \"你好\"})</code>,调用 <code>greet(\"小明\", \"早上好\")</code> 会发生什么?",
|
||
"opts": [
|
||
"编译警告但能运行",
|
||
"greeting 变为 null",
|
||
"正常执行,greeting 为 \"早上好\"",
|
||
"编译报错:命名参数不能按位置传参"
|
||
],
|
||
"ans": 3,
|
||
"exp": "<code>{}</code> 包裹的是<b>命名参数</b>,必须写成 <code>greet(\"小明\", greeting: \"早上好\")</code>;<code>[]</code> 才是可选位置参数。命名参数让调用意图清晰,是团队协作中常用的做法。"
|
||
},
|
||
{
|
||
"lv": 2,
|
||
"q": "写\"重试发送验证码\"逻辑:要求<b>至少发送一次</b>,失败则继续重试。哪种循环语义最贴切?",
|
||
"opts": [
|
||
"<code>for</code>",
|
||
"<code>while</code>",
|
||
"<code>repeat</code>",
|
||
"<code>do-while</code>"
|
||
],
|
||
"ans": 3,
|
||
"exp": "<b>do-while</b> 先执行循环体再判断条件,保证至少执行一次,正是\"先发一次、不行再重试\"的语义。while 先判断后执行,可能一次都不执行。"
|
||
},
|
||
{
|
||
"lv": 3,
|
||
"q": "实现\"删除待办\"功能,<code>list.remove(3)</code> 和 <code>list.removeAt(3)</code> 的区别是?",
|
||
"opts": [
|
||
"remove 按值删除,removeAt 按下标删除",
|
||
"remove 会删除所有等于 3 的元素",
|
||
"两者完全相同",
|
||
"remove 删下标,removeAt 按值删除"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<code>remove(value)</code> 删除<b>第一个</b>值相等的元素并返回是否成功;<code>removeAt(index)</code> 按下标删除并返回被删的元素,越界抛 RangeError。写代码前想清楚你要删的是\"值\"还是\"位置\"。"
|
||
},
|
||
{
|
||
"lv": 3,
|
||
"q": "解析接口数据:用 <code>data[\"name\"]</code> 取一个<b>不存在的 key</b> 时,返回什么?",
|
||
"opts": [
|
||
"null",
|
||
"空字符串",
|
||
"抛异常",
|
||
"抛出 NoSuchMethodError"
|
||
],
|
||
"ans": 0,
|
||
"exp": "Map 用 <code>[]</code> 取值时,key 不存在<b>返回 null</b> 而不是抛异常。所以 <code>data[\"name\"]</code> 可能为 null,取值后判空再使用是常规操作(配合 <code>??</code> 兜底)。"
|
||
},
|
||
{
|
||
"lv": 3,
|
||
"q": "配置列表按条件插入元素:<code>var l = [1, 2, if (isVip) 3];</code> 当 <code>isVip</code> 为 false 时 l 是?",
|
||
"opts": [
|
||
"<code>[1, 2, 3]</code>",
|
||
"编译错误",
|
||
"<code>[1, 2, false]</code>",
|
||
"<code>[1, 2]</code>"
|
||
],
|
||
"ans": 3,
|
||
"exp": "这是 <b>collection-if</b> 语法:条件不成立时该元素直接不生成。Flutter 里常用于条件渲染组件列表,配合 <code>...</code> 展开和 collection-for 一起使用。"
|
||
},
|
||
{
|
||
"lv": 3,
|
||
"q": "两个用户各自关注了一批标签,要找出<b>共同关注</b>的标签,用哪种写法?",
|
||
"opts": [
|
||
"<code>a.intersect(b)</code>",
|
||
"<code>a.toSet().intersection(b.toSet())</code>",
|
||
"<code>a.union(b)</code>",
|
||
"<code>a & b</code>"
|
||
],
|
||
"ans": 1,
|
||
"exp": "List 没有交集方法,要先转 Set。<code>intersection()</code> 返回两个集合的共同元素;<code>union()</code> 是并集。注意方法名是 <code>intersection()</code>,不是其它语言的 <code>intersect()</code>。"
|
||
},
|
||
{
|
||
"lv": 3,
|
||
"q": "计算购物车总价:<code>List<double> prices = [];</code> 空列表调用 <code>prices.reduce((a, b) => a + b)</code> 会?",
|
||
"opts": [
|
||
"返回空列表",
|
||
"抛出 StateError 异常",
|
||
"返回 0",
|
||
"返回 null"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<code>reduce</code> 要求列表<b>至少有一个元素</b>,空列表直接抛 \"Bad state: No element\"。更稳的写法是 <code>fold(0, (a, b) => a + b)</code>:带初始值,空列表返回 0。"
|
||
},
|
||
{
|
||
"lv": 4,
|
||
"q": "写日期工具类,希望 <code>DateUtil.parse(\"2024-01-01\")</code> 在字符串不合法时返回 null 而不是抛异常,用哪种构造函数?",
|
||
"opts": [
|
||
"const 构造函数",
|
||
"命名构造函数",
|
||
"普通构造函数",
|
||
"factory 构造函数"
|
||
],
|
||
"ans": 3,
|
||
"exp": "<b>factory</b> 构造函数可以不返回新实例——可以返回缓存实例、子类实例,甚至返回 null。它把\"按需创建/校验\"的逻辑封装在构造入口,调用方写法统一且安全。"
|
||
},
|
||
{
|
||
"lv": 4,
|
||
"q": "日志打印、权限检查这类能力要被多个<b>互不相关</b>的类复用,又不想强制继承关系,Dart 的推荐做法是?",
|
||
"opts": [
|
||
"<code>extends</code> 继承",
|
||
"<code>with</code> 混入 Mixin",
|
||
"<code>implements</code> 实现",
|
||
"<code>abstract</code> 抽象类"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<b>Mixin</b>(<code>with</code>)把可复用逻辑抽出来按需混入,避免\"为了复用而强行继承\"的长继承链。Flutter 源码大量使用,如 <code>class _X with RouteAware</code>。"
|
||
},
|
||
{
|
||
"lv": 4,
|
||
"q": "类内部要声明一个\"仅供本文件使用\"的私有字段,正确写法是?",
|
||
"opts": [
|
||
"<code>-String token;</code>",
|
||
"<code>#token</code>",
|
||
"<code>private String _token;</code>",
|
||
"<code>String _token;</code>"
|
||
],
|
||
"ans": 3,
|
||
"exp": "Dart 没有 <code>private</code> 关键字,以<b>下划线开头</b>表示库内私有:<code>_token</code>。注意这是\"库\"级别私有(同文件可见),不是类级别。"
|
||
},
|
||
{
|
||
"lv": 4,
|
||
"q": "用户类的 <code>name</code> 字段希望<b>赋值时自动去掉首尾空格</b>,最佳做法是?",
|
||
"opts": [
|
||
"用 static 修饰",
|
||
"直接写公共字段,调用方自己 trim",
|
||
"声明 getter/setter,在 setter 里 trim",
|
||
"用 final 禁止修改"
|
||
],
|
||
"ans": 2,
|
||
"exp": "<b>setter</b> 在赋值入口统一处理,所有调用方(包括构造函数)都自动享受规范化,不用每个地方都记得 trim。写法:<code>String get name</code> 与 <code>set name(String v)</code>。"
|
||
},
|
||
{
|
||
"lv": 4,
|
||
"q": "<code>class Dog implements Animal</code> 与 <code>extends</code> 继承的关键区别是?",
|
||
"opts": [
|
||
"extends 要求实现全部成员",
|
||
"implements 只能用于抽象类",
|
||
"implements 要求实现 Animal 的<b>全部</b>成员(含字段),extends 可复用已有实现",
|
||
"两者完全一样"
|
||
],
|
||
"ans": 2,
|
||
"exp": "<code>implements</code> 把 Animal 当<b>接口</b>:所有成员都要自己重写,即使父类已有实现;<code>extends</code> 继承实现,只覆写需要改的部分。implements 用于\"规定能力\",extends 用于\"复用实现\"。"
|
||
},
|
||
{
|
||
"lv": 5,
|
||
"q": "用户对象可能为 null:<code>User? u = await fetchUser();</code>,以下哪种使用方式更安全?",
|
||
"opts": [
|
||
"<code>print(u?.name ?? \"\");</code>",
|
||
"A 和 C 都可以",
|
||
"<code>if (u != null) { print(u!.name); }</code> 必须加 !",
|
||
"<code>if (u != null) { print(u.name); }</code> 判空后直接用 u"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<b>A</b>:局部变量判空后编译器会<b>自动提升</b>为非空类型,直接使用即可;<b>C</b>:<code>?.</code> 安全调用 + <code>??</code> 兜底,一行搞定。只有被闭包捕获的变量才需要 <code>!</code>。"
|
||
},
|
||
{
|
||
"lv": 5,
|
||
"q": "详情页要同时请求\"用户信息\"和\"订单列表\"两个接口,都拿到再渲染,用哪个方法?",
|
||
"opts": [
|
||
"串行写两个 await",
|
||
"<code>Future.delayed</code> 等待",
|
||
"<code>Future.wait([fetchUser(), fetchOrders()])</code>",
|
||
"<code>Future.any</code>"
|
||
],
|
||
"ans": 2,
|
||
"exp": "<b>Future.wait</b> 并发启动多个 Future,全部完成后统一返回结果列表,总耗时约等于最慢的那个;串行 await 则是两个请求耗时相加。<code>Future.any</code> 只等第一个完成的。"
|
||
},
|
||
{
|
||
"lv": 5,
|
||
"q": "某个字段要等登录成功后才能赋值,但又想声明成非空类型,正确声明方式是?",
|
||
"opts": [
|
||
"<code>late String token;</code>",
|
||
"<code>final token = null;</code>",
|
||
"<code>dynamic token;</code>",
|
||
"<code>String? token = \"\";</code>"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<b>late</b> 表示\"推迟初始化,首次访问时才赋值\",适合依赖异步结果的字段或计算代价高的属性。注意:late 变量在赋值前被访问会抛 LateInitializationError。"
|
||
},
|
||
{
|
||
"lv": 5,
|
||
"q": "把解析结果转成目标类型:<code>var age = data[\"age\"] as int;</code>,当 age 实际是 String 时会发生?",
|
||
"opts": [
|
||
"返回 null",
|
||
"自动转成 int",
|
||
"抛出 TypeError(类型转换失败)",
|
||
"静默忽略"
|
||
],
|
||
"ans": 2,
|
||
"exp": "<code>as</code> 是<b>强制类型转换</b>,类型不符立即抛异常。安全做法:先用 <code>is</code> 判断类型,或先统一规范数据(如 num 一律 <code>.toInt()</code>)。"
|
||
},
|
||
{
|
||
"lv": 5,
|
||
"q": "对可能为 null 的 <code>String? s</code> 使用 <code>s!</code>,若 s 确实为 null 会?",
|
||
"opts": [
|
||
"编译错误",
|
||
"返回 null",
|
||
"静默继续",
|
||
"抛出 TypeError(空检查失败)"
|
||
],
|
||
"ans": 3,
|
||
"exp": "<code>!</code> 是<b>强制解包</b>运算符,向编译器承诺\"这里不可能为 null\",承诺落空时运行时抛 TypeError。能用判空提升或 <code>??</code> 的地方尽量别用 <code>!</code>,减少运行时崩溃点。"
|
||
},
|
||
{
|
||
"lv": 6,
|
||
"q": "Flutter 中常见 <code>ButtonStyle()..backgroundColor = ... ..shape = ...</code> 写法,<code>..</code> 级联操作符的核心行为是?",
|
||
"opts": [
|
||
"与 <code>...</code> 展开等价",
|
||
"只能用于 List",
|
||
"链式调用并返回最后一次结果",
|
||
"对同一对象连续操作且返回对象本身"
|
||
],
|
||
"ans": 3,
|
||
"exp": "<b>级联操作符</b> <code>..</code> 对同一对象连续执行多个操作,<b>不改变返回值</b>(始终是原对象),适合集中配置对象。<code>.</code> 返回的是方法调用的返回值,两者行为不同。"
|
||
},
|
||
{
|
||
"lv": 6,
|
||
"q": "Dart 3 中,函数想直接返回\"用户名 + 年龄\"这组小数据,又不想专门建一个类,推荐用?",
|
||
"opts": [
|
||
"<code>List<dynamic></code>",
|
||
"Record 记录类型:<code>(String name, int age)</code>",
|
||
"用全局变量",
|
||
"<code>Map<String, dynamic></code>"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<b>Record</b> 是 Dart 3 的轻量聚合类型:<code>var r = (\"张三\", 18);</code> 或命名字段 <code>(name: \"张三\", age: 18)</code>,用 <code>r.$1</code> / <code>r.name</code> 取值,还能配合模式匹配解构,比 Map 更类型安全。"
|
||
},
|
||
{
|
||
"lv": 6,
|
||
"q": "Dart 3 的 switch 可以直接当表达式赋值:<code>var s = switch (status) { \"ok\" => \"成功\", _ => \"未知\" };</code> 这种写法?",
|
||
"opts": [
|
||
"只能匹配字符串",
|
||
"合法:switch 表达式返回一个值",
|
||
"非法:switch 不能作表达式",
|
||
"必须每个分支加 break"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<b>switch 表达式</b>用 <code>=></code> 代替冒号,整体作为值赋给变量,配合模式匹配可以解构、判断类型,比旧式 switch 简洁,也天然避免了漏 break 的坑。"
|
||
},
|
||
{
|
||
"lv": 6,
|
||
"q": "想给系统类 <code>String</code> 加一个 <code>isEmail()</code> 方法,但 String 不能改源码,用?",
|
||
"opts": [
|
||
"继承 String",
|
||
"用 mixin 混入",
|
||
"<b>extension</b> 扩展:<code>extension EmailCheck on String { bool isEmail() {...} }</code>",
|
||
"写静态工具类"
|
||
],
|
||
"ans": 2,
|
||
"exp": "<b>extension</b> 可以不修改原类给已有类型添加方法,之后 <code>\"a@b.com\".isEmail()</code> 直接调用。注意扩展方法是静态分发(编译期决定),不参与运行时多态。"
|
||
},
|
||
{
|
||
"lv": 6,
|
||
"q": "泛型容器 <code>class Box<T extends num> {}</code> 中 <code>extends num</code> 的含义是?",
|
||
"opts": [
|
||
"T 必须可空",
|
||
"T 可以是任意类型",
|
||
"T 必须是集合类型",
|
||
"T 只能是 int、double 等数值类型"
|
||
],
|
||
"ans": 3,
|
||
"exp": "<b>泛型约束</b>限定 T 必须是 num 及其子类(int/double),这样 Box 内部就能安全调用数值运算。不加约束时 T 等价于 <code>Object?</code>。"
|
||
}
|
||
]
|
||
}
|