Files
2026-08-10 00:15:44 +08:00

374 lines
18 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"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": "写优惠逻辑:订单数 &gt; 10 打 9 折,&gt; 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 &gt; 10 先成立就直接取 0.9,后面的 else if 不再执行。正确写法应把范围大的条件放前面(先判断 &gt; 50)。判断顺序是 if-else 链最经典的坑。"
},
{
"lv": 2,
"q": "接口返回 <code>Map&lt;String, dynamic&gt; 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&lt;double&gt; 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&lt;dynamic&gt;</code>",
"Record 记录类型:<code>(String name, int age)</code>",
"用全局变量",
"<code>Map&lt;String, dynamic&gt;</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\" =&gt; \"成功\", _ =&gt; \"未知\" };</code> 这种写法?",
"opts": [
"只能匹配字符串",
"合法:switch 表达式返回一个值",
"非法:switch 不能作表达式",
"必须每个分支加 break"
],
"ans": 1,
"exp": "<b>switch 表达式</b>用 <code>=&gt;</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&lt;T extends num&gt; {}</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>。"
}
]
}