1666 lines
70 KiB
JSON
1666 lines
70 KiB
JSON
{
|
||
"sets": [
|
||
{
|
||
"id": 1,
|
||
"name": "Dart & Flutter 学习测验",
|
||
"questions": [
|
||
{
|
||
"id": 1,
|
||
"lv": 1,
|
||
"q": "Dart 中声明\"类型自动推断\"的变量,用哪个关键字?",
|
||
"opts": [
|
||
"var",
|
||
"let",
|
||
"const",
|
||
"dynamic"
|
||
],
|
||
"ans": 0,
|
||
"exp": "Dart 用 <b>var</b> 由编译器自动推断类型;<b>let</b> 是 JS 的;<b>const</b> 表示编译期常量。"
|
||
},
|
||
{
|
||
"id": 2,
|
||
"lv": 1,
|
||
"q": "Dart 中表示 64 位整数的数据类型是?",
|
||
"opts": [
|
||
"integer",
|
||
"int",
|
||
"number",
|
||
"long"
|
||
],
|
||
"ans": 1,
|
||
"exp": "Dart 用 <b>int</b> 表示整数(64位),<b>double</b> 表示浮点数,两者父类是 <b>num</b>。"
|
||
},
|
||
{
|
||
"id": 3,
|
||
"lv": 1,
|
||
"q": "以下哪个是 Dart 中正确的单行注释写法?",
|
||
"opts": [
|
||
"# 注释",
|
||
"/* 注释 */",
|
||
"// 注释",
|
||
"<!-- 注释 -->"
|
||
],
|
||
"ans": 2,
|
||
"exp": "Dart 单行注释用 <b>//</b>,多行用 <b>/* */</b>。<b>#</b> 是 Python,#! 在 Dart 中只是 shebang 声明。"
|
||
},
|
||
{
|
||
"id": 4,
|
||
"lv": 1,
|
||
"q": "Dart 程序的入口函数是?",
|
||
"opts": [
|
||
"runApp()",
|
||
"main()",
|
||
"init()",
|
||
"start()"
|
||
],
|
||
"ans": 1,
|
||
"exp": "入口是 <b>main()</b>。Flutter 中通常写成 <code>void main() => runApp(MyApp());</code>"
|
||
},
|
||
{
|
||
"id": 5,
|
||
"lv": 1,
|
||
"q": "要在控制台输出文字,应调用哪个函数?",
|
||
"opts": [
|
||
"console.log()",
|
||
"System.out.println()",
|
||
"echo",
|
||
"print()"
|
||
],
|
||
"ans": 3,
|
||
"exp": "Dart 用 <b>print()</b> 输出到控制台,比如 <code>print(\"Hello Dart\");</code>"
|
||
},
|
||
{
|
||
"id": 6,
|
||
"lv": 1,
|
||
"q": "<code>int x = 10;</code> 要打印出 <code>x=10</code>,以下哪种写法正确?",
|
||
"opts": [
|
||
"print(\"x=\" + x);",
|
||
"print(\"x=$x\");",
|
||
"print('x=${x}');",
|
||
"以上都可以"
|
||
],
|
||
"ans": 3,
|
||
"exp": "Dart 中 <b>+</b> 拼接字符串、<b>$x</b> 插值、<b>${x}</b> 表达式插值都合法,三种写法均能输出 <code>x=10</code>。"
|
||
},
|
||
{
|
||
"id": 7,
|
||
"lv": 2,
|
||
"q": "以下哪个 <b>不是</b> Dart 的循环写法?",
|
||
"opts": [
|
||
"for (var i=0; i<5; i++)",
|
||
"while (ok)",
|
||
"foreach (x in list)",
|
||
"do { } while (ok)"
|
||
],
|
||
"ans": 2,
|
||
"exp": "Dart <b>没有</b> <code>foreach(x in list)</code> 语法,应写 <code>for (var x in list)</code> 或 <code>list.forEach(...)</code>。"
|
||
},
|
||
{
|
||
"id": 8,
|
||
"lv": 2,
|
||
"q": "执行 <code>for (var i=0; i<5; i++) print(i);</code> 会输出?",
|
||
"opts": [
|
||
"1 2 3 4 5",
|
||
"0 1 2 3 4",
|
||
"0 1 2 3 4 5",
|
||
"5 4 3 2 1"
|
||
],
|
||
"ans": 1,
|
||
"exp": "i 从 0 开始,条件 <code>i<5</code>,所以输出 <b>0 1 2 3 4</b>。"
|
||
},
|
||
{
|
||
"id": 9,
|
||
"lv": 2,
|
||
"q": "Dart 的 switch 语句中,每个 case 结束必须以什么结尾(否则编译报错)?",
|
||
"opts": [
|
||
"end",
|
||
"return / break / throw",
|
||
"continue",
|
||
"逗号"
|
||
],
|
||
"ans": 1,
|
||
"exp": "Dart 每个非空 case 必须以 <b>break、return 或 throw</b> 等结束,不能像 C 语言那样自动穿透。"
|
||
},
|
||
{
|
||
"id": 10,
|
||
"lv": 2,
|
||
"q": "定义一个返回两数之和的函数,哪个写法正确?",
|
||
"opts": [
|
||
"int add(int a,int b){ return a+b; }",
|
||
"add(int a,int b) => a+b;",
|
||
"void add(int a,int b){ return a+b; }",
|
||
"A 和 B 都可以"
|
||
],
|
||
"ans": 3,
|
||
"exp": "A 是传统写法,B 是<b>箭头函数</b>简写(返回表达式),两者都合法;C 返回 void 却 return 值,编译错误。"
|
||
},
|
||
{
|
||
"id": 11,
|
||
"lv": 2,
|
||
"q": "以下哪个是<b>可选命名参数</b>的正确声明?",
|
||
"opts": [
|
||
"void f({String name}) {}",
|
||
"void f([String name]) {}",
|
||
"void f(String? name) {}",
|
||
"void f(String name=\"\") {}"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<b>{}</b> 包裹的是命名参数(调用用 <code>f(name: x)</code>);<b>[]</b> 是可选位置参数;<b>?</b> 是空安全;最后一个是默认值写法但不属于命名参数。"
|
||
},
|
||
{
|
||
"id": 12,
|
||
"lv": 2,
|
||
"q": "函数 <code>void f({int a = 1}) {}</code>,以下调用哪个正确?",
|
||
"opts": [
|
||
"f()",
|
||
"f(1)",
|
||
"f(a: 1)",
|
||
"A 和 C 都可以"
|
||
],
|
||
"ans": 3,
|
||
"exp": "命名参数有默认值时可省略(A 合法);必须<b>按名调用</b> <code>f(a: 1)</code>(C 合法);<code>f(1)</code> 用位置传参给命名参数会报错。"
|
||
},
|
||
{
|
||
"id": 13,
|
||
"lv": 3,
|
||
"q": "Dart 中表示\"数组/列表\"的类型是?",
|
||
"opts": [
|
||
"Array",
|
||
"ArrayList",
|
||
"List",
|
||
"Vector"
|
||
],
|
||
"ans": 2,
|
||
"exp": "Dart 用 <b>List</b>(可增长数组),字面量写法 <code>[1,2,3]</code>。"
|
||
},
|
||
{
|
||
"id": 14,
|
||
"lv": 3,
|
||
"q": "创建包含 1、2、3 的列表,正确的是?",
|
||
"opts": [
|
||
"{1, 2, 3}",
|
||
"[1, 2, 3]",
|
||
"(1, 2, 3)",
|
||
"List(1,2,3)"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<b>[]</b> 是 List;<b>{}</b> 是 Set/Map;<b>()</b> 不是集合字面量。"
|
||
},
|
||
{
|
||
"id": 15,
|
||
"lv": 3,
|
||
"q": "<code>var list = [10, 20, 30]; print(list[1]);</code> 输出?",
|
||
"opts": [
|
||
"10",
|
||
"20",
|
||
"30",
|
||
"报错"
|
||
],
|
||
"ans": 1,
|
||
"exp": "Dart 索引从 <b>0</b> 开始,list[1] 是第二个元素 <b>20</b>。"
|
||
},
|
||
{
|
||
"id": 16,
|
||
"lv": 3,
|
||
"q": "对 List 每个元素做处理并<b>返回一个新集合</b>的方法是?",
|
||
"opts": [
|
||
"forEach()",
|
||
"map()",
|
||
"where()",
|
||
"add()"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<b>map()</b> 对每个元素变换并返回 Iterable;<b>forEach()</b> 只遍历返回 void;<b>where()</b> 是过滤。"
|
||
},
|
||
{
|
||
"id": 17,
|
||
"lv": 3,
|
||
"q": "<code>var a=[1,2,3]; var b=[0, ...a];</code> 那么 <code>b.length</code> 是?",
|
||
"opts": [
|
||
"3",
|
||
"4",
|
||
"7",
|
||
"报错"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<b>...a</b> 是扩展运算符,把 a 展开成 1,2,3,加上开头的 0,b = [0,1,2,3],长度 <b>4</b>。"
|
||
},
|
||
{
|
||
"id": 18,
|
||
"lv": 3,
|
||
"q": "以下哪种集合类型<b>保证元素不重复</b>?",
|
||
"opts": [
|
||
"List",
|
||
"Map",
|
||
"Set",
|
||
"Queue"
|
||
],
|
||
"ans": 2,
|
||
"exp": "<b>Set</b> 存储唯一元素,重复添加会被忽略;Map 存储键值对,键也不重复。"
|
||
},
|
||
{
|
||
"id": 19,
|
||
"lv": 4,
|
||
"q": "定义类 <code>class Dog { String name; }</code> 后,创建一个实例哪个正确?",
|
||
"opts": [
|
||
"Dog d = Dog();",
|
||
"var d = new Dog;",
|
||
"Dog d = new Dog();",
|
||
"以上都可以"
|
||
],
|
||
"ans": 3,
|
||
"exp": "Dart 2 之后 <b>new 关键字可选</b>,且省略括号的 <code>Dog()</code> 也合法,三种写法都能创建实例。"
|
||
},
|
||
{
|
||
"id": 20,
|
||
"lv": 4,
|
||
"q": "子类继承父类使用哪个关键字?",
|
||
"opts": [
|
||
"with",
|
||
"implements",
|
||
"extends",
|
||
"inherits"
|
||
],
|
||
"ans": 2,
|
||
"exp": "继承用 <b>extends</b>;<b>implements</b> 是实现接口;<b>with</b> 用于混入 Mixin。"
|
||
},
|
||
{
|
||
"id": 21,
|
||
"lv": 4,
|
||
"q": "包含未实现方法、<b>不能被直接实例化</b>的类,用什么关键字声明?",
|
||
"opts": [
|
||
"abstract",
|
||
"interface",
|
||
"base",
|
||
"pure"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<b>abstract</b> 抽象类可含未实现方法,不能直接 new,需子类实现后实例化。"
|
||
},
|
||
{
|
||
"id": 22,
|
||
"lv": 4,
|
||
"q": "在构造函数/实例方法中,<code>this</code> 指向?",
|
||
"opts": [
|
||
"当前实例",
|
||
"父类对象",
|
||
"类本身",
|
||
"静态成员"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<b>this</b> 指向当前实例对象,用于区分参数与成员变量,如 <code>this.name = name</code>。"
|
||
},
|
||
{
|
||
"id": 23,
|
||
"lv": 4,
|
||
"q": "创建一个只能装 String 的 List,哪个写法正确?",
|
||
"opts": [
|
||
"List<String> names = [];",
|
||
"List names = <String>[];",
|
||
"var names = <String>[];",
|
||
"以上都是"
|
||
],
|
||
"ans": 3,
|
||
"exp": "Dart 泛型语法多样:类型标注式、泛型字面量 <code><String>[]</code> 都合法,三种写法结果相同。"
|
||
},
|
||
{
|
||
"id": 24,
|
||
"lv": 4,
|
||
"q": "抽象类 Animal 有抽象方法 <code>void speak()</code>,子类 Dog 必须?",
|
||
"opts": [
|
||
"重写 speak() 提供实现",
|
||
"调用父类构造",
|
||
"删除 speak",
|
||
"什么也不用做"
|
||
],
|
||
"ans": 0,
|
||
"exp": "子类必须用 <code>@override</code> 实现所有抽象方法,否则 Dog 也是抽象类无法实例化。"
|
||
},
|
||
{
|
||
"id": 25,
|
||
"lv": 5,
|
||
"q": "Dart 空安全中,声明一个<b>可能为 null</b> 的字符串类型是?",
|
||
"opts": [
|
||
"String",
|
||
"String?",
|
||
"String!",
|
||
"nullable String"
|
||
],
|
||
"ans": 1,
|
||
"exp": "在类型后加 <b>?</b> 表示可空:<code>String? s = null;</code>;不加 ? 的 String 保证非空。"
|
||
},
|
||
{
|
||
"id": 26,
|
||
"lv": 5,
|
||
"q": "空值合并运算符 <code>??</code> 的作用是?",
|
||
"opts": [
|
||
"若左边为 null 则返回右边",
|
||
"强制把 null 变为非空",
|
||
"判断对象是否相等",
|
||
"抛出空异常"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<code>a ?? b</code>:a 不为 null 用 a,否则用 b。常配合 <code>??=</code> 设置默认值。"
|
||
},
|
||
{
|
||
"id": 27,
|
||
"lv": 5,
|
||
"q": "使用 <code>async/await</code> 时,异步函数一般返回什么类型?",
|
||
"opts": [
|
||
"Stream<T>",
|
||
"Future<T>",
|
||
"void",
|
||
"T"
|
||
],
|
||
"ans": 1,
|
||
"exp": "async 函数返回 <b>Future<T></b>,await 会挂起等待该 Future 完成后再继续执行。"
|
||
},
|
||
{
|
||
"id": 28,
|
||
"lv": 5,
|
||
"q": "执行以下代码,输出顺序是?<br><code>Future.delayed(Duration(seconds:1), () => print(\"A\"));<br>print(\"B\");</code>",
|
||
"opts": [
|
||
"A 后 B",
|
||
"B 后 A",
|
||
"同时输出",
|
||
"只输出 A"
|
||
],
|
||
"ans": 1,
|
||
"exp": "Future.delayed 是异步任务,先执行同步的 <code>print(\"B\")</code>,1 秒后再输出 A。"
|
||
},
|
||
{
|
||
"id": 29,
|
||
"lv": 6,
|
||
"q": "Flutter 中用于<b>监听持续不断的数据流</b>(如多次事件)的是?",
|
||
"opts": [
|
||
"Future",
|
||
"Stream",
|
||
"List",
|
||
"Map"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<b>Stream</b> 可监听多次异步事件;Future 只代表一次性的结果。"
|
||
},
|
||
{
|
||
"id": 30,
|
||
"lv": 6,
|
||
"q": "Flutter 中构建界面的<b>基本单位</b>是?",
|
||
"opts": [
|
||
"Activity",
|
||
"View",
|
||
"Widget",
|
||
"Component"
|
||
],
|
||
"ans": 2,
|
||
"exp": "Flutter 一切皆 <b>Widget</b>,UI 由 Widget 树组合而成(如 Text、Container、Column)。"
|
||
},
|
||
{
|
||
"id": 31,
|
||
"lv": 6,
|
||
"q": "界面状态需要<b>随数据变化而更新</b>时,应使用哪类组件?",
|
||
"opts": [
|
||
"StatelessWidget",
|
||
"StatefulWidget",
|
||
"Container",
|
||
"Scaffold"
|
||
],
|
||
"ans": 1,
|
||
"exp": "有动态状态用 <b>StatefulWidget</b>(配合 State 里的 setState 刷新);无状态用 StatelessWidget。"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": 9,
|
||
"name": "Dart 开发实战",
|
||
"questions": [
|
||
{
|
||
"id": 98,
|
||
"lv": 1,
|
||
"q": "开发注册页时,用户输入的年龄是字符串,需要转成 <code>int</code> 保存。已知 <code>String ageText = \"18\";</code>,正确的转换写法是?",
|
||
"opts": [
|
||
"<code>int(ageText)</code>",
|
||
"<code>toInt(ageText)</code>",
|
||
"<code>int.parse(ageText)</code>",
|
||
"<code>ageText.parseInt()</code>"
|
||
],
|
||
"ans": 2,
|
||
"exp": "<code>int.parse()</code> 把字符串解析成整数,解析失败会抛 FormatException,更稳妥的是 <code>int.tryParse()</code>(失败返回 null)。注意 Dart 没有 <code>\"18\".parseInt()</code> 这种写法,<code>int(...)</code> 也不是转换函数。"
|
||
},
|
||
{
|
||
"id": 99,
|
||
"lv": 1,
|
||
"q": "项目里要定义一个\"永远不允许修改\"的 API 地址常量,以下哪种声明最合适?",
|
||
"opts": [
|
||
"<code>final String api = \"https://api.example.com\";</code>",
|
||
"<code>const String api = \"https://api.example.com\";</code>",
|
||
"<code>String api = \"https://api.example.com\";</code>",
|
||
"<code>var api = \"https://api.example.com\";</code>"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<b>const</b> 是编译期常量:值在编译时就确定,且不可变,编译器可直接内联替换,还能配合 const 构造函数做实例复用。<b>final</b> 是运行期赋值一次后不可变。给字面量常量用 const 是更优选择。"
|
||
},
|
||
{
|
||
"id": 100,
|
||
"lv": 1,
|
||
"q": "你在重构代码时写下:<code>var x = 10; x = \"hello\";</code> 会发生什么?",
|
||
"opts": [
|
||
"正常运行,x 变成字符串",
|
||
"编译报错:x 已被推断为 int 类型",
|
||
"运行时报错",
|
||
"x 自动变为 null"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<b>var</b> 声明时由初始值自动推断类型,推断后类型就<b>固定</b>了:x 是 int,再赋 String 在编译期直接报错。想存任意类型,应显式声明 <code>dynamic</code> 或 <code>Object?</code>。"
|
||
},
|
||
{
|
||
"id": 101,
|
||
"lv": 1,
|
||
"q": "给变量起名时,以下哪个<b>不是</b>合法的 Dart 标识符?",
|
||
"opts": [
|
||
"<code>_score</code>",
|
||
"<code>2x</code>",
|
||
"<code>中文名</code>",
|
||
"<code>name_2</code>"
|
||
],
|
||
"ans": 1,
|
||
"exp": "Dart 标识符<b>不能以数字开头</b>。<code>_score</code> 合法(下划线开头表示库内私有,是 Dart 的约定俗成);Dart 支持 Unicode 标识符,中文变量名同样合法。"
|
||
},
|
||
{
|
||
"id": 102,
|
||
"lv": 1,
|
||
"q": "结算功能计算人均消费:<code>int total = 10; int people = 4; double avg = total / people;</code> 打印 <code>avg</code> 得到?",
|
||
"opts": [
|
||
"2",
|
||
"2.5",
|
||
"2.0",
|
||
"报错"
|
||
],
|
||
"ans": 1,
|
||
"exp": "Dart 中 <b>int 除以 int 的结果一定是 double</b>:10 / 4 = 2.5。想得到整除结果用 <code>~/</code>:<code>10 ~/ 4 == 2</code>,取余用 <code>%</code>。"
|
||
},
|
||
{
|
||
"id": 103,
|
||
"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.8",
|
||
"0.9",
|
||
"1.0",
|
||
"0.7"
|
||
],
|
||
"ans": 1,
|
||
"exp": "if-else 链<b>从上到下匹配,命中即止</b>:60 > 10 先成立就直接取 0.9,后面的 else if 不再执行。正确写法应把范围大的条件放前面(先判断 > 50)。判断顺序是 if-else 链最经典的坑。"
|
||
},
|
||
{
|
||
"id": 104,
|
||
"lv": 2,
|
||
"q": "接口返回 <code>Map<String, dynamic> data</code>,想遍历所有 key 打印出来,以下哪种写法正确?",
|
||
"opts": [
|
||
"<code>for (var k in data) print(k);</code>",
|
||
"<code>for (var k in data.keys) print(k);</code>",
|
||
"<code>data.keys.forEach(print);</code>",
|
||
"B 和 C 都可以"
|
||
],
|
||
"ans": 3,
|
||
"exp": "Map 本身<b>不能</b>直接 for-in 遍历,要先取 <code>keys</code> / <code>values</code> / <code>entries</code>。B 是标准写法;C 中 <code>forEach(print)</code> 利用了函数引用,同样正确。两种都行,按团队规范选择。"
|
||
},
|
||
{
|
||
"id": 105,
|
||
"lv": 2,
|
||
"q": "写一个返回用户名的函数:<code>String getUserName() { }</code>,忘了写 <code>return</code>,会怎样?",
|
||
"opts": [
|
||
"返回 null",
|
||
"编译报错",
|
||
"运行时崩溃",
|
||
"自动返回空字符串"
|
||
],
|
||
"ans": 1,
|
||
"exp": "空安全下,声明了非空返回类型 <code>String</code> 的函数<b>必须有 return</b>,漏写直接编译报错,把隐患消灭在编译期。如果确实允许无返回值,应把返回类型声明为 <code>String?</code>。"
|
||
},
|
||
{
|
||
"id": 106,
|
||
"lv": 2,
|
||
"q": "问候函数:<code>void greet(String name, {String greeting = \"你好\"})</code>,调用 <code>greet(\"小明\", \"早上好\")</code> 会发生什么?",
|
||
"opts": [
|
||
"正常执行,greeting 为 \"早上好\"",
|
||
"编译报错:命名参数不能按位置传参",
|
||
"greeting 变为 null",
|
||
"编译警告但能运行"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<code>{}</code> 包裹的是<b>命名参数</b>,必须写成 <code>greet(\"小明\", greeting: \"早上好\")</code>;<code>[]</code> 才是可选位置参数。命名参数让调用意图清晰,是团队协作中常用的做法。"
|
||
},
|
||
{
|
||
"id": 107,
|
||
"lv": 2,
|
||
"q": "写\"重试发送验证码\"逻辑:要求<b>至少发送一次</b>,失败则继续重试。哪种循环语义最贴切?",
|
||
"opts": [
|
||
"<code>while</code>",
|
||
"<code>do-while</code>",
|
||
"<code>for</code>",
|
||
"<code>repeat</code>"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<b>do-while</b> 先执行循环体再判断条件,保证至少执行一次,正是\"先发一次、不行再重试\"的语义。while 先判断后执行,可能一次都不执行。"
|
||
},
|
||
{
|
||
"id": 108,
|
||
"lv": 3,
|
||
"q": "实现\"删除待办\"功能,<code>list.remove(3)</code> 和 <code>list.removeAt(3)</code> 的区别是?",
|
||
"opts": [
|
||
"remove 按值删除,removeAt 按下标删除",
|
||
"两者完全相同",
|
||
"remove 删下标,removeAt 按值删除",
|
||
"remove 会删除所有等于 3 的元素"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<code>remove(value)</code> 删除<b>第一个</b>值相等的元素并返回是否成功;<code>removeAt(index)</code> 按下标删除并返回被删的元素,越界抛 RangeError。写代码前想清楚你要删的是\"值\"还是\"位置\"。"
|
||
},
|
||
{
|
||
"id": 109,
|
||
"lv": 3,
|
||
"q": "解析接口数据:用 <code>data[\"name\"]</code> 取一个<b>不存在的 key</b> 时,返回什么?",
|
||
"opts": [
|
||
"抛异常",
|
||
"null",
|
||
"空字符串",
|
||
"抛出 NoSuchMethodError"
|
||
],
|
||
"ans": 1,
|
||
"exp": "Map 用 <code>[]</code> 取值时,key 不存在<b>返回 null</b> 而不是抛异常。所以 <code>data[\"name\"]</code> 可能为 null,取值后判空再使用是常规操作(配合 <code>??</code> 兜底)。"
|
||
},
|
||
{
|
||
"id": 110,
|
||
"lv": 3,
|
||
"q": "配置列表按条件插入元素:<code>var l = [1, 2, if (isVip) 3];</code> 当 <code>isVip</code> 为 false 时 l 是?",
|
||
"opts": [
|
||
"<code>[1, 2]</code>",
|
||
"<code>[1, 2, 3]</code>",
|
||
"<code>[1, 2, false]</code>",
|
||
"编译错误"
|
||
],
|
||
"ans": 0,
|
||
"exp": "这是 <b>collection-if</b> 语法:条件不成立时该元素直接不生成。Flutter 里常用于条件渲染组件列表,配合 <code>...</code> 展开和 collection-for 一起使用。"
|
||
},
|
||
{
|
||
"id": 111,
|
||
"lv": 3,
|
||
"q": "两个用户各自关注了一批标签,要找出<b>共同关注</b>的标签,用哪种写法?",
|
||
"opts": [
|
||
"<code>a & b</code>",
|
||
"<code>a.intersect(b)</code>",
|
||
"<code>a.toSet().intersection(b.toSet())</code>",
|
||
"<code>a.union(b)</code>"
|
||
],
|
||
"ans": 2,
|
||
"exp": "List 没有交集方法,要先转 Set。<code>intersection()</code> 返回两个集合的共同元素;<code>union()</code> 是并集。注意方法名是 <code>intersection()</code>,不是其它语言的 <code>intersect()</code>。"
|
||
},
|
||
{
|
||
"id": 112,
|
||
"lv": 3,
|
||
"q": "计算购物车总价:<code>List<double> prices = [];</code> 空列表调用 <code>prices.reduce((a, b) => a + b)</code> 会?",
|
||
"opts": [
|
||
"返回 0",
|
||
"抛出 StateError 异常",
|
||
"返回 null",
|
||
"返回空列表"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<code>reduce</code> 要求列表<b>至少有一个元素</b>,空列表直接抛 \"Bad state: No element\"。更稳的写法是 <code>fold(0, (a, b) => a + b)</code>:带初始值,空列表返回 0。"
|
||
},
|
||
{
|
||
"id": 113,
|
||
"lv": 4,
|
||
"q": "写日期工具类,希望 <code>DateUtil.parse(\"2024-01-01\")</code> 在字符串不合法时返回 null 而不是抛异常,用哪种构造函数?",
|
||
"opts": [
|
||
"factory 构造函数",
|
||
"普通构造函数",
|
||
"命名构造函数",
|
||
"const 构造函数"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<b>factory</b> 构造函数可以不返回新实例——可以返回缓存实例、子类实例,甚至返回 null。它把\"按需创建/校验\"的逻辑封装在构造入口,调用方写法统一且安全。"
|
||
},
|
||
{
|
||
"id": 114,
|
||
"lv": 4,
|
||
"q": "日志打印、权限检查这类能力要被多个<b>互不相关</b>的类复用,又不想强制继承关系,Dart 的推荐做法是?",
|
||
"opts": [
|
||
"<code>extends</code> 继承",
|
||
"<code>implements</code> 实现",
|
||
"<code>with</code> 混入 Mixin",
|
||
"<code>abstract</code> 抽象类"
|
||
],
|
||
"ans": 2,
|
||
"exp": "<b>Mixin</b>(<code>with</code>)把可复用逻辑抽出来按需混入,避免\"为了复用而强行继承\"的长继承链。Flutter 源码大量使用,如 <code>class _X with RouteAware</code>。"
|
||
},
|
||
{
|
||
"id": 115,
|
||
"lv": 4,
|
||
"q": "类内部要声明一个\"仅供本文件使用\"的私有字段,正确写法是?",
|
||
"opts": [
|
||
"<code>private String _token;</code>",
|
||
"<code>String _token;</code>",
|
||
"<code>-String token;</code>",
|
||
"<code>#token</code>"
|
||
],
|
||
"ans": 1,
|
||
"exp": "Dart 没有 <code>private</code> 关键字,以<b>下划线开头</b>表示库内私有:<code>_token</code>。注意这是\"库\"级别私有(同文件可见),不是类级别。"
|
||
},
|
||
{
|
||
"id": 116,
|
||
"lv": 4,
|
||
"q": "用户类的 <code>name</code> 字段希望<b>赋值时自动去掉首尾空格</b>,最佳做法是?",
|
||
"opts": [
|
||
"声明 getter/setter,在 setter 里 trim",
|
||
"直接写公共字段,调用方自己 trim",
|
||
"用 final 禁止修改",
|
||
"用 static 修饰"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<b>setter</b> 在赋值入口统一处理,所有调用方(包括构造函数)都自动享受规范化,不用每个地方都记得 trim。写法:<code>String get name</code> 与 <code>set name(String v)</code>。"
|
||
},
|
||
{
|
||
"id": 117,
|
||
"lv": 4,
|
||
"q": "<code>class Dog implements Animal</code> 与 <code>extends</code> 继承的关键区别是?",
|
||
"opts": [
|
||
"implements 要求实现 Animal 的<b>全部</b>成员(含字段),extends 可复用已有实现",
|
||
"两者完全一样",
|
||
"implements 只能用于抽象类",
|
||
"extends 要求实现全部成员"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<code>implements</code> 把 Animal 当<b>接口</b>:所有成员都要自己重写,即使父类已有实现;<code>extends</code> 继承实现,只覆写需要改的部分。implements 用于\"规定能力\",extends 用于\"复用实现\"。"
|
||
},
|
||
{
|
||
"id": 118,
|
||
"lv": 5,
|
||
"q": "用户对象可能为 null:<code>User? u = await fetchUser();</code>,以下哪种使用方式更安全?",
|
||
"opts": [
|
||
"<code>if (u != null) { print(u.name); }</code> 判空后直接用 u",
|
||
"<code>if (u != null) { print(u!.name); }</code> 必须加 !",
|
||
"<code>print(u?.name ?? \"\");</code>",
|
||
"A 和 C 都可以"
|
||
],
|
||
"ans": 3,
|
||
"exp": "<b>A</b>:局部变量判空后编译器会<b>自动提升</b>为非空类型,直接使用即可;<b>C</b>:<code>?.</code> 安全调用 + <code>??</code> 兜底,一行搞定。只有被闭包捕获的变量才需要 <code>!</code>。"
|
||
},
|
||
{
|
||
"id": 119,
|
||
"lv": 5,
|
||
"q": "详情页要同时请求\"用户信息\"和\"订单列表\"两个接口,都拿到再渲染,用哪个方法?",
|
||
"opts": [
|
||
"<code>Future.wait([fetchUser(), fetchOrders()])</code>",
|
||
"串行写两个 await",
|
||
"<code>Future.any</code>",
|
||
"<code>Future.delayed</code> 等待"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<b>Future.wait</b> 并发启动多个 Future,全部完成后统一返回结果列表,总耗时约等于最慢的那个;串行 await 则是两个请求耗时相加。<code>Future.any</code> 只等第一个完成的。"
|
||
},
|
||
{
|
||
"id": 120,
|
||
"lv": 5,
|
||
"q": "某个字段要等登录成功后才能赋值,但又想声明成非空类型,正确声明方式是?",
|
||
"opts": [
|
||
"<code>late String token;</code>",
|
||
"<code>String? token = \"\";</code>",
|
||
"<code>dynamic token;</code>",
|
||
"<code>final token = null;</code>"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<b>late</b> 表示\"推迟初始化,首次访问时才赋值\",适合依赖异步结果的字段或计算代价高的属性。注意:late 变量在赋值前被访问会抛 LateInitializationError。"
|
||
},
|
||
{
|
||
"id": 121,
|
||
"lv": 5,
|
||
"q": "把解析结果转成目标类型:<code>var age = data[\"age\"] as int;</code>,当 age 实际是 String 时会发生?",
|
||
"opts": [
|
||
"返回 null",
|
||
"抛出 TypeError(类型转换失败)",
|
||
"静默忽略",
|
||
"自动转成 int"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<code>as</code> 是<b>强制类型转换</b>,类型不符立即抛异常。安全做法:先用 <code>is</code> 判断类型,或先统一规范数据(如 num 一律 <code>.toInt()</code>)。"
|
||
},
|
||
{
|
||
"id": 122,
|
||
"lv": 5,
|
||
"q": "对可能为 null 的 <code>String? s</code> 使用 <code>s!</code>,若 s 确实为 null 会?",
|
||
"opts": [
|
||
"返回 null",
|
||
"抛出 TypeError(空检查失败)",
|
||
"静默继续",
|
||
"编译错误"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<code>!</code> 是<b>强制解包</b>运算符,向编译器承诺\"这里不可能为 null\",承诺落空时运行时抛 TypeError。能用判空提升或 <code>??</code> 的地方尽量别用 <code>!</code>,减少运行时崩溃点。"
|
||
},
|
||
{
|
||
"id": 123,
|
||
"lv": 6,
|
||
"q": "Flutter 中常见 <code>ButtonStyle()..backgroundColor = ... ..shape = ...</code> 写法,<code>..</code> 级联操作符的核心行为是?",
|
||
"opts": [
|
||
"对同一对象连续操作且返回对象本身",
|
||
"链式调用并返回最后一次结果",
|
||
"只能用于 List",
|
||
"与 <code>...</code> 展开等价"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<b>级联操作符</b> <code>..</code> 对同一对象连续执行多个操作,<b>不改变返回值</b>(始终是原对象),适合集中配置对象。<code>.</code> 返回的是方法调用的返回值,两者行为不同。"
|
||
},
|
||
{
|
||
"id": 124,
|
||
"lv": 6,
|
||
"q": "Dart 3 中,函数想直接返回\"用户名 + 年龄\"这组小数据,又不想专门建一个类,推荐用?",
|
||
"opts": [
|
||
"<code>Map<String, dynamic></code>",
|
||
"Record 记录类型:<code>(String name, int age)</code>",
|
||
"<code>List<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 更类型安全。"
|
||
},
|
||
{
|
||
"id": 125,
|
||
"lv": 6,
|
||
"q": "Dart 3 的 switch 可以直接当表达式赋值:<code>var s = switch (status) { \"ok\" => \"成功\", _ => \"未知\" };</code> 这种写法?",
|
||
"opts": [
|
||
"合法:switch 表达式返回一个值",
|
||
"非法:switch 不能作表达式",
|
||
"必须每个分支加 break",
|
||
"只能匹配字符串"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<b>switch 表达式</b>用 <code>=></code> 代替冒号,整体作为值赋给变量,配合模式匹配可以解构、判断类型,比旧式 switch 简洁,也天然避免了漏 break 的坑。"
|
||
},
|
||
{
|
||
"id": 126,
|
||
"lv": 6,
|
||
"q": "想给系统类 <code>String</code> 加一个 <code>isEmail()</code> 方法,但 String 不能改源码,用?",
|
||
"opts": [
|
||
"<b>extension</b> 扩展:<code>extension EmailCheck on String { bool isEmail() {...} }</code>",
|
||
"继承 String",
|
||
"用 mixin 混入",
|
||
"写静态工具类"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<b>extension</b> 可以不修改原类给已有类型添加方法,之后 <code>\"a@b.com\".isEmail()</code> 直接调用。注意扩展方法是静态分发(编译期决定),不参与运行时多态。"
|
||
},
|
||
{
|
||
"id": 127,
|
||
"lv": 6,
|
||
"q": "泛型容器 <code>class Box<T extends num> {}</code> 中 <code>extends num</code> 的含义是?",
|
||
"opts": [
|
||
"T 只能是 int、double 等数值类型",
|
||
"T 可以是任意类型",
|
||
"T 必须可空",
|
||
"T 必须是集合类型"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<b>泛型约束</b>限定 T 必须是 num 及其子类(int/double),这样 Box 内部就能安全调用数值运算。不加约束时 T 等价于 <code>Object?</code>。"
|
||
}
|
||
],
|
||
"lvNames": [
|
||
"基础语法",
|
||
"控制流与函数",
|
||
"集合",
|
||
"面向对象",
|
||
"空安全与异步",
|
||
"Dart 高级特性"
|
||
]
|
||
},
|
||
{
|
||
"id": 10,
|
||
"name": "Flutter 开发实战",
|
||
"questions": [
|
||
{
|
||
"id": 128,
|
||
"lv": 1,
|
||
"q": "新建 Flutter 项目后,把应用真正跑起来的入口代码是?",
|
||
"opts": [
|
||
"<code>void main() => runApp(MyApp());</code>",
|
||
"<code>void main() { MyApp(); }</code>",
|
||
"<code>runApp() { MyApp }</code>",
|
||
"<code>main() { MaterialApp(); }</code>"
|
||
],
|
||
"ans": 0,
|
||
"exp": "Dart 程序入口是 <code>main()</code>,Flutter 通过 <code>runApp(Widget)</code> 把根组件挂载到引擎上。注意 <code>MyApp()</code> 是创建 Widget 实例,不能少了括号。"
|
||
},
|
||
{
|
||
"id": 129,
|
||
"lv": 1,
|
||
"q": "实现一个\"3 秒倒计时\"按钮,每秒刷新显示剩余秒数,应使用?",
|
||
"opts": [
|
||
"StatelessWidget",
|
||
"StatefulWidget",
|
||
"Container",
|
||
"Scaffold"
|
||
],
|
||
"ans": 1,
|
||
"exp": "有<b>动态变化的数据</b>(倒计时数字)就需要 StatefulWidget:数据保存在 State 里,变化时调 <code>setState()</code> 刷新。没有可变状态时应优先用 StatelessWidget。"
|
||
},
|
||
{
|
||
"id": 130,
|
||
"lv": 1,
|
||
"q": "界面上要显示一行固定文案\"登录成功\",最合适的组件是?",
|
||
"opts": [
|
||
"Text",
|
||
"Label",
|
||
"Paragraph",
|
||
"RichText"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<code>Text</code> 是最常用的文本组件,可通过 style 配置字号、颜色、字重等。RichText 用于一段文字中混排多种样式的富文本场景。"
|
||
},
|
||
{
|
||
"id": 131,
|
||
"lv": 1,
|
||
"q": "点击\"确认\"按钮后分数要 +1 并立即显示到界面,正确流程是?",
|
||
"opts": [
|
||
"修改 State 字段后调用 <code>setState()</code>",
|
||
"直接修改字段就行",
|
||
"重启整个 App",
|
||
"修改 Widget 的构造参数"
|
||
],
|
||
"ans": 0,
|
||
"exp": "State 里的字段只是普通数据,必须调用 <code>setState()</code> 通知框架\"数据变了\",框架才会重新执行 build 刷新 UI。注意 setState 只重建<b>当前 State 的子树</b>,不是整棵树。"
|
||
},
|
||
{
|
||
"id": 132,
|
||
"lv": 1,
|
||
"q": "要展示 10000 条商品记录,性能最优的做法是?",
|
||
"opts": [
|
||
"<code>ListView.builder</code>(按需构建可见项)",
|
||
"Column 里循环放 10000 个组件",
|
||
"SingleChildScrollView 包 Column",
|
||
"GridView.count 全部构建"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<code>ListView.builder</code> 只构建<b>当前可见</b>的列表项(懒加载),滚动时回收复用;Column + for 会一次性构建全部组件,万条数据直接卡死。数据量大优先 builder 系列。"
|
||
},
|
||
{
|
||
"id": 133,
|
||
"lv": 2,
|
||
"q": "登录页要垂直排列\"输入框、输入框、登录按钮\",用哪个布局组件?",
|
||
"opts": [
|
||
"Column",
|
||
"Row",
|
||
"Stack",
|
||
"Wrap"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<code>Column</code> 垂直方向排列子组件,<code>Row</code> 水平方向,<code>Stack</code> 叠加并支持定位,<code>Wrap</code> 在空间不足时自动换行。"
|
||
},
|
||
{
|
||
"id": 134,
|
||
"lv": 2,
|
||
"q": "Row 里想让一个按钮<b>占满剩余宽度</b>(剩余空间全给它),按钮外层套?",
|
||
"opts": [
|
||
"<code>Expanded</code>",
|
||
"<code>Padding</code>",
|
||
"<code>Center</code>",
|
||
"<code>Spacer</code>"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<code>Expanded</code> 让子组件占据主轴的剩余空间(Row 的主轴是水平方向)。多个 Expanded 可通过 flex 参数按比例分配空间。"
|
||
},
|
||
{
|
||
"id": 135,
|
||
"lv": 2,
|
||
"q": "Column 里有几个按钮,想让它们在<b>水平方向居中</b>,应该设置?",
|
||
"opts": [
|
||
"<code>crossAxisAlignment: CrossAxisAlignment.center</code>",
|
||
"<code>mainAxisAlignment: MainAxisAlignment.center</code>",
|
||
"<code>alignment: Alignment.center</code>",
|
||
"<code>textAlign: TextAlign.center</code>"
|
||
],
|
||
"ans": 0,
|
||
"exp": "Column 的<b>主轴是垂直</b>方向、<b>交叉轴是水平</b>方向。水平居中=沿交叉轴居中=crossAxisAlignment.center;mainAxisAlignment 控制的是垂直方向。主/交叉轴搞反是新手最常踩的坑。"
|
||
},
|
||
{
|
||
"id": 136,
|
||
"lv": 2,
|
||
"q": "封面图要<b>铺满整个区域且不拉伸变形</b>(多出的部分裁掉),fit 参数应该用?",
|
||
"opts": [
|
||
"<code>BoxFit.cover</code>",
|
||
"<code>BoxFit.fill</code>",
|
||
"<code>BoxFit.none</code>",
|
||
"<code>BoxFit.scaleDown</code>"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<b>cover</b>:等比缩放填满、超出裁剪,常用于头像、封面;<b>fill</b> 会拉伸变形;<b>contain</b> 完整显示但可能留白;<b>none</b> 不缩放。"
|
||
},
|
||
{
|
||
"id": 137,
|
||
"lv": 2,
|
||
"q": "商品名过长时希望<b>单行显示,超出部分显示省略号</b>,Text 的配置是?",
|
||
"opts": [
|
||
"<code>maxLines: 1, overflow: TextOverflow.ellipsis</code>",
|
||
"只设 overflow: TextOverflow.clip",
|
||
"只设 maxLines: 3",
|
||
"<code>softWrap: false</code> 就够了"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<code>maxLines</code> 限制最大行数 + <code>overflow: TextOverflow.ellipsis</code> 指定超出的表现(省略号/裁剪/fade),两者配合才能出现\"…\"效果。"
|
||
},
|
||
{
|
||
"id": 138,
|
||
"lv": 3,
|
||
"q": "输入框需要\"预填默认值 + 按钮点击后读取内容 + 随时清空\",推荐用?",
|
||
"opts": [
|
||
"<code>TextEditingController</code>",
|
||
"每次读 onChanged 参数",
|
||
"GlobalKey 临时查找",
|
||
"无法实现"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<code>TextEditingController</code> 是输入框的\"数据源\":<code>TextEditingController(text: \"预填\")</code> 初始化,<code>controller.text</code> 读取,<code>controller.clear()</code> 清空。用完后在 dispose 里释放。"
|
||
},
|
||
{
|
||
"id": 139,
|
||
"lv": 3,
|
||
"q": "页面销毁时,取消监听、释放 Controller 的代码应该写在哪里?",
|
||
"opts": [
|
||
"<code>dispose()</code>",
|
||
"<code>initState()</code>",
|
||
"<code>build()</code>",
|
||
"<code>didChangeDependencies()</code>"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<code>dispose()</code> 是 State 被移除时的清理钩子:取消 Timer、Stream 订阅、释放 Controller。不清理会造成内存泄漏和 \"setState called after dispose\" 报错。"
|
||
},
|
||
{
|
||
"id": 140,
|
||
"lv": 3,
|
||
"q": "登录状态、用户信息要被<b>多个页面共享</b>,又不想层层传构造参数,项目常用方案是?",
|
||
"opts": [
|
||
"Provider / InheritedWidget",
|
||
"定义全局变量直接读写",
|
||
"每个页面重新请求接口",
|
||
"把状态塞进路由参数"
|
||
],
|
||
"ans": 0,
|
||
"exp": "Flutter 官方的底层方案是 <b>InheritedWidget</b>,<b>Provider</b> 是对它的优雅封装:共享数据放顶层,子组件 <code>context.watch()</code> 取用并自动刷新。全局变量没有通知机制,页面不会自动更新。"
|
||
},
|
||
{
|
||
"id": 141,
|
||
"lv": 3,
|
||
"q": "商品列表页要支持<b>下拉刷新</b>,应该把 ListView 包进哪个组件?",
|
||
"opts": [
|
||
"<code>RefreshIndicator</code>",
|
||
"<code>GestureDetector</code>",
|
||
"<code>AnimatedList</code>",
|
||
"<code>Scrollbar</code>"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<code>RefreshIndicator</code> 包住可滚动组件,配合 <code>onRefresh</code> 返回的 Future 实现下拉刷新动画。这是 Material 规范自带的下拉刷新方案。"
|
||
},
|
||
{
|
||
"id": 142,
|
||
"lv": 3,
|
||
"q": "App 切到后台、再回到前台时,需要暂停/恢复计时器,通过什么监听?",
|
||
"opts": [
|
||
"<code>WidgetsBindingObserver</code>",
|
||
"<code>RouteObserver</code>",
|
||
"<code>NavigatorObserver</code>",
|
||
"<code>MediaQuery</code>"
|
||
],
|
||
"ans": 0,
|
||
"exp": "给 State 混入 <code>with WidgetsBindingObserver</code>,在 <code>didChangeAppLifecycleState()</code> 中监听 AppLifecycleState(paused / resumed / inactive),即可感知前后台切换。"
|
||
},
|
||
{
|
||
"id": 143,
|
||
"lv": 4,
|
||
"q": "列表页点击商品跳转详情页,标准写法是?",
|
||
"opts": [
|
||
"<code>Navigator.push(context, MaterialPageRoute(builder: (_) => DetailPage(id: id)))</code>",
|
||
"<code>Navigator.go(DetailPage(id: id))</code>",
|
||
"<code>Route.open(DetailPage())</code>",
|
||
"<code>DetailPage(id: id).show()</code>"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<code>Navigator.push</code> 把新路由压入导航栈,MaterialPageRoute 提供转场动画,返回上一页用 <code>Navigator.pop(context)</code>。"
|
||
},
|
||
{
|
||
"id": 144,
|
||
"lv": 4,
|
||
"q": "详情页编辑完要把结果<b>回传给列表页</b>,详情页返回时应该写?",
|
||
"opts": [
|
||
"<code>Navigator.pop(context, result)</code>",
|
||
"<code>Navigator.back(result)</code>",
|
||
"<code>Navigator.pushResult(result)</code>",
|
||
"<code>context.popAndPush(result)</code>"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<code>pop(context, 返回值)</code> 的第二个参数就是回传的数据,列表页 <code>await push(...)</code> 的返回值即可收到。注意 pop 的参数是\"返回给上一页的数据\",不是新路由。"
|
||
},
|
||
{
|
||
"id": 145,
|
||
"lv": 4,
|
||
"q": "跳转时需要传递商品 id、名称等参数,团队协作中<b>最推荐</b>的传参方式是?",
|
||
"opts": [
|
||
"<code>DetailPage(id: 1, name: \"商品\")</code> 构造参数传递",
|
||
"全局变量临时存",
|
||
"static 静态字段存",
|
||
"URL 字符串拼接"
|
||
],
|
||
"ans": 0,
|
||
"exp": "构造参数显式、类型安全、可读性好——跳转处一眼看到传了什么。全局变量/静态字段是隐藏依赖,页面多起来后非常难维护。"
|
||
},
|
||
{
|
||
"id": 146,
|
||
"lv": 4,
|
||
"q": "在 App 里注册命名路由(如 <code>/login</code>、<code>/home</code>),配置位置是?",
|
||
"opts": [
|
||
"<code>MaterialApp(routes: {...})</code>",
|
||
"<code>main()</code> 函数里",
|
||
"<code>runApp()</code> 参数",
|
||
"每个页面里各自声明"
|
||
],
|
||
"ans": 0,
|
||
"exp": "命名路由集中配置在 <code>MaterialApp</code> 的 <code>routes</code> 表,之后用 <code>Navigator.pushNamed(context, \"/login\")</code> 跳转;需要传参时配合 <code>arguments</code> 参数。"
|
||
},
|
||
{
|
||
"id": 147,
|
||
"lv": 4,
|
||
"q": "跳到选择页,用户选完返回后要根据<b>选择结果</b>继续处理,列表页怎么写?",
|
||
"opts": [
|
||
"<code>final r = await Navigator.push(...);</code> 拿到返回值再处理",
|
||
"无法等待结果",
|
||
"用 setState 轮询",
|
||
"跳转时把回调函数传过去"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<code>push</code> 返回 <code>Future<T></code>,await 后拿到 pop 回传的值,再执行后续逻辑(如刷新选中项)。这是\"页面间取结果\"的标准姿势。"
|
||
},
|
||
{
|
||
"id": 148,
|
||
"lv": 5,
|
||
"q": "接口返回 JSON 字符串,执行 <code>var data = jsonDecode(text);</code> 后 data 的类型是?",
|
||
"opts": [
|
||
"<code>dynamic</code>(实际可能是 Map 或 List)",
|
||
"<code>String</code>",
|
||
"<code>Map<String, dynamic></code>",
|
||
"<code>Object</code>"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<code>jsonDecode</code> 的返回类型是 <code>dynamic</code>:JSON 对象变 Map<String, dynamic>、数组变 List<dynamic>、数字/布尔原样返回。通常需要手动转换:<code>jsonDecode(text) as Map<String, dynamic></code>。"
|
||
},
|
||
{
|
||
"id": 149,
|
||
"lv": 5,
|
||
"q": "要把用户对象 <code>User(id: 1, name: \"张三\")</code> 转成 JSON 字符串发给服务器,正确流程是?",
|
||
"opts": [
|
||
"给 User 写 <code>toJson()</code>,再 <code>jsonEncode(user.toJson())</code>",
|
||
"<code>jsonEncode(user)</code> 直接序列化",
|
||
"<code>user.toString()</code>",
|
||
"<code>JSON.stringify(user)</code>"
|
||
],
|
||
"ans": 0,
|
||
"exp": "Dart 默认不会自动序列化任意对象,惯例是模型类自己实现 <code>Map<String, dynamic> toJson()</code>,再用 <code>jsonEncode</code> 转字符串;反序列化则对应 <code>User.fromJson(Map)</code> 工厂构造。"
|
||
},
|
||
{
|
||
"id": 150,
|
||
"lv": 5,
|
||
"q": "网络请求可能超时/断网,用户点\"登录\"时抛出了异常,正确的处理是?",
|
||
"opts": [
|
||
"用 try-catch 包裹 await 请求,捕获异常并提示用户",
|
||
"不做处理",
|
||
"打印日志后忽略",
|
||
"延迟 3 秒自动重试"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<code>try { await api.login(...) } catch (e) { 提示\"网络异常,请重试\" }</code> 是最基础的错误处理;生产环境还会区分 SocketException(断网)、TimeoutException(超时)等做分类提示。"
|
||
},
|
||
{
|
||
"id": 151,
|
||
"lv": 5,
|
||
"q": "请求进行中需要展示\"加载中\"状态,最合适用?",
|
||
"opts": [
|
||
"<code>CircularProgressIndicator</code>",
|
||
"Text(\"加载中...\")",
|
||
"Opacity 半透明遮罩",
|
||
"AnimatedContainer 闪烁"
|
||
],
|
||
"ans": 0,
|
||
"exp": "Material 标准的加载指示器是 <code>CircularProgressIndicator</code>(转圈)和 <code>LinearProgressIndicator</code>(条),配合 loading 状态变量做条件渲染。"
|
||
},
|
||
{
|
||
"id": 152,
|
||
"lv": 5,
|
||
"q": "http 请求要设置 10 秒超时,正确写法是?",
|
||
"opts": [
|
||
"<code>await http.get(url).timeout(Duration(seconds: 10))</code>",
|
||
"<code>http.get(url, timeout: 10)</code>",
|
||
"<code>Timer(Duration(seconds: 10), ...)</code>",
|
||
"<code>Future.any</code> 自动超时"
|
||
],
|
||
"ans": 0,
|
||
"exp": "Future 自带 <code>.timeout()</code>:超时抛 TimeoutException,可再接 <code>onTimeout</code> 参数兜底。http 包本身没有 timeout 参数,这是常见的误解。"
|
||
},
|
||
{
|
||
"id": 153,
|
||
"lv": 6,
|
||
"q": "首页同时请求\"轮播图、公告、商品列表\"三个接口,全部完成再渲染页面,用?",
|
||
"opts": [
|
||
"<code>Future.wait([...])</code> 并发等待",
|
||
"三个 await 串行",
|
||
"依次 catch 分别显示",
|
||
"用 <code>Future.any</code>"
|
||
],
|
||
"ans": 0,
|
||
"exp": "并发场景用 <code>Future.wait</code>,总耗时约等于最慢的请求而不是三个相加。生产上可配合记录单个请求失败做局部降级(某块失败不影响整页)。"
|
||
},
|
||
{
|
||
"id": 154,
|
||
"lv": 6,
|
||
"q": "商品列表滑到底部要自动加载下一页,监听滚动的方案是?",
|
||
"opts": [
|
||
"<code>ScrollController</code> 监听 pixels 接近 maxScrollExtent 时触发",
|
||
"用 Timer 每 3 秒加载",
|
||
"下拉刷新代替",
|
||
"GestureDetector 监听手势"
|
||
],
|
||
"ans": 0,
|
||
"exp": "给 ListView 挂 <code>ScrollController</code>,在 <code>addListener</code> 里判断 <code>position.pixels >= position.maxScrollExtent - 200</code>(预留阈值)就加载下一页,配合 loading 状态防止重复触发。"
|
||
},
|
||
{
|
||
"id": 155,
|
||
"lv": 6,
|
||
"q": "商品标题中要<b>红色高亮\"热卖\"二字</b>、其余部分灰色,用?",
|
||
"opts": [
|
||
"<code>RichText</code> + <code>TextSpan</code> 组合不同样式",
|
||
"拆成多个 Text 排一排",
|
||
"用换行符拼接字符串",
|
||
"TextStyle 做不到,只能整段同色"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<code>RichText</code> 的 <code>TextSpan</code> 支持树状嵌套:每个 span 可以有自己的 style,是\"一段文字多种样式\"的标准方案。"
|
||
},
|
||
{
|
||
"id": 156,
|
||
"lv": 6,
|
||
"q": "界面出现<b>黄黑条纹</b>溢出警告(RenderFlex overflowed),说明?",
|
||
"opts": [
|
||
"子组件超出了父组件给定的约束空间",
|
||
"主题颜色配置错误",
|
||
"内存泄漏",
|
||
"字体加载失败"
|
||
],
|
||
"ans": 0,
|
||
"exp": "Row/Column 空间不够时子组件溢出,debug 模式显示黄黑条纹并打印 \"RenderFlex overflowed by XX pixels\"。解决思路:Expanded/Flexible 让出空间、SingleChildScrollView 滚动、FittedBox 缩放。"
|
||
},
|
||
{
|
||
"id": 157,
|
||
"lv": 6,
|
||
"q": "瀑布流商品图列表很卡、图片解码占内存高,优先优化手段是?",
|
||
"opts": [
|
||
"<code>cacheWidth</code> / <code>ResizeImage</code> 限制解码尺寸",
|
||
"给图片加圆角",
|
||
"提高图片的清晰度",
|
||
"减少列表项数量"
|
||
],
|
||
"ans": 0,
|
||
"exp": "Image.network 默认按原图尺寸解码,一张 4000px 大图在手机上就是内存杀手。用 <code>cacheWidth: 300</code> 或 <code>ResizeImage</code> 让引擎按需解码成小尺寸位图,内存占用和滚动性能立竿见影。"
|
||
}
|
||
],
|
||
"lvNames": [
|
||
"Widget 基础",
|
||
"布局与组件",
|
||
"状态管理",
|
||
"路由与导航",
|
||
"数据与网络",
|
||
"实战综合"
|
||
]
|
||
},
|
||
{
|
||
"id": 11,
|
||
"name": "Dart 基础巩固",
|
||
"lvNames": [
|
||
"基础语法",
|
||
"控制流与函数",
|
||
"集合",
|
||
"面向对象",
|
||
"空安全与异步",
|
||
"Dart 高级特性"
|
||
],
|
||
"questions": [
|
||
{
|
||
"id": 158,
|
||
"lv": 1,
|
||
"q": "Dart 中布尔类型 <code>bool</code> 的字面量写法是?",
|
||
"opts": [
|
||
"<code>TRUE</code>",
|
||
"<code>true</code>",
|
||
"<code>1</code>",
|
||
"<code>yes</code>"
|
||
],
|
||
"ans": 1,
|
||
"exp": "bool 只有两个值:<b>true</b> 和 <b>false</b>(全小写)。TRUE、1、yes 都不是 Dart 的合法写法。"
|
||
},
|
||
{
|
||
"id": 159,
|
||
"lv": 1,
|
||
"q": "要存储 3.14 这样的浮点数,应声明为什么类型?",
|
||
"opts": [
|
||
"<code>float</code>",
|
||
"<code>decimal</code>",
|
||
"<code>big</code>",
|
||
"<code>double</code>"
|
||
],
|
||
"ans": 3,
|
||
"exp": "浮点数用 <b>double</b>,整数用 <b>int</b>,两者的共同父类是 <b>num</b>。Dart 没有 float、decimal 类型。"
|
||
},
|
||
{
|
||
"id": 160,
|
||
"lv": 1,
|
||
"q": "定义一个内容跨多行的字符串,应该用哪组引号包裹?",
|
||
"opts": [
|
||
"<code>'''</code> 三个单引号(或 <code>\"\"\"</code>)",
|
||
"<code>\"</code> 单个双引号",
|
||
"<code>'</code> 单个单引号",
|
||
"<code>`</code> 反引号"
|
||
],
|
||
"ans": 0,
|
||
"exp": "三个单引号 <code>'''</code> 或三个双引号 <code>\"\"\"</code> 包裹的字符串<b>可以直接跨行书写</b>,换行会被保留;单引号/双引号字符串内不能直接换行。Dart 没有反引号模板字符串。"
|
||
},
|
||
{
|
||
"id": 161,
|
||
"lv": 1,
|
||
"q": "关于 Dart 字符串的特性,以下说法正确的是?",
|
||
"opts": [
|
||
"字符串创建后可随意修改内部字符",
|
||
"字符串只能用双引号包裹",
|
||
"字符串方法返回新字符串,原字符串不变",
|
||
"字符串本质是数字类型"
|
||
],
|
||
"ans": 2,
|
||
"exp": "Dart 字符串<b>不可变</b>:<code>toUpperCase()</code> 等方法返回<b>新字符串</b>,原值不变。频繁拼接字符串时建议用 <b>StringBuffer</b> 提升性能。"
|
||
},
|
||
{
|
||
"id": 162,
|
||
"lv": 1,
|
||
"q": "<code>String s = \"Hello\";</code> 要得到全大写的 \"HELLO\",应调用?",
|
||
"opts": [
|
||
"<code>s.upper()</code>",
|
||
"<code>s.toUpperCase()</code>",
|
||
"<code>s.up()</code>",
|
||
"<code>String.upper(s)</code>"
|
||
],
|
||
"ans": 1,
|
||
"exp": "转大写用 <b>s.toUpperCase()</b>,转小写用 <code>s.toLowerCase()</code>。注意返回的是<b>新字符串</b>,原字符串不变。"
|
||
},
|
||
{
|
||
"id": 163,
|
||
"lv": 1,
|
||
"q": "把数字 42 转成字符串 \"42\",正确写法是?",
|
||
"opts": [
|
||
"<code>(String) 42</code>",
|
||
"<code>int.stringify(42)</code>",
|
||
"<code>42.toString()</code>",
|
||
"<code>String.valueOf(42)</code>"
|
||
],
|
||
"ans": 2,
|
||
"exp": "调用 <b>toString()</b>:<code>42.toString()</code>。注意 double 的 toString 会带小数:<code>3.0.toString()</code> 得到 \"3.0\"。(String) 强转、String.valueOf 是其它语言的习惯,Dart 没有。"
|
||
},
|
||
{
|
||
"id": 164,
|
||
"lv": 2,
|
||
"q": "取 a、b 中较大的值,用一行表达式应写?",
|
||
"opts": [
|
||
"<code>a ?? b</code>",
|
||
"<code>a > b ? a : b</code>",
|
||
"<code>a || b</code>",
|
||
"<code>a && b</code>"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<b>三元运算符</b> <code>条件 ? 表达式1 : 表达式2</code>:条件成立取第一个,否则取第二个。<code>a ?? b</code> 是空值合并(a 为 null 才取 b),|| 和 && 是逻辑运算,都不能比较大小。"
|
||
},
|
||
{
|
||
"id": 165,
|
||
"lv": 2,
|
||
"q": "<code>bool ok = false; print(ok && check());</code> 中 check() 会被执行吗?",
|
||
"opts": [
|
||
"会执行",
|
||
"报错",
|
||
"不会执行,&& 左侧为 false 时短路",
|
||
"执行两次"
|
||
],
|
||
"ans": 2,
|
||
"exp": "<b>短路求值</b>:<code>&&</code> 左侧为 false 时结果已确定为 false,<b>右侧不会执行</b>;<code>||</code> 左侧为 true 时同理。常用于安全判断:<code>user != null && user.isVip</code>。"
|
||
},
|
||
{
|
||
"id": 166,
|
||
"lv": 2,
|
||
"q": "循环里要<b>跳过当前这一次迭代</b>、继续下一次,用哪个关键字?",
|
||
"opts": [
|
||
"<code>break</code>",
|
||
"<code>return</code>",
|
||
"<code>continue</code>",
|
||
"<code>skip</code>"
|
||
],
|
||
"ans": 2,
|
||
"exp": "<b>continue</b> 结束本次迭代、立即进入下一轮;<b>break</b> 直接退出整个循环;return 退出的是整个函数。"
|
||
},
|
||
{
|
||
"id": 167,
|
||
"lv": 2,
|
||
"q": "<code>var f = (x) => x * 2;</code> 这种没有名字的函数写法是?",
|
||
"opts": [
|
||
"命名函数",
|
||
"构造函数",
|
||
"静态函数",
|
||
"匿名函数(Lambda 表达式)"
|
||
],
|
||
"ans": 3,
|
||
"exp": "箭头 <b>=></b> 配合无名参数列表就是<b>匿名函数 / Lambda</b>,常作为回调、比较器传递:<code>list.sort((a, b) => a - b)</code>。"
|
||
},
|
||
{
|
||
"id": 168,
|
||
"lv": 2,
|
||
"q": "<code>void greet(String name, [String word = \"你好\"])</code>,调用 <code>greet(\"小明\")</code> 时 word 的值是?",
|
||
"opts": [
|
||
"<code>null</code>",
|
||
"报错",
|
||
"<code>\"你好\"</code>",
|
||
"空字符串"
|
||
],
|
||
"ans": 2,
|
||
"exp": "<b>[ ]</b> 包裹的是<b>可选位置参数</b>,不传时使用默认值 <b>\"你好\"</b>。它与命名参数({} 包裹、必须按名传)不同,是按顺序传参的:<code>greet(\"小明\", \"早上好\")</code>。"
|
||
},
|
||
{
|
||
"id": 169,
|
||
"lv": 2,
|
||
"q": "循环里要<b>立即终止整个循环</b>,用哪个关键字?",
|
||
"opts": [
|
||
"<code>break</code>",
|
||
"<code>continue</code>",
|
||
"<code>exit</code>",
|
||
"<code>stop</code>"
|
||
],
|
||
"ans": 0,
|
||
"exp": "<b>break</b> 立即结束当前循环;continue 只跳过本次。break 也常用于 switch 的 case 结尾——Dart 要求非空 case 必须以 break、return、throw 等结束。"
|
||
},
|
||
{
|
||
"id": 170,
|
||
"lv": 3,
|
||
"q": "<code>var data = {'name': '张三', 'age': 18};</code> data 的类型是?",
|
||
"opts": [
|
||
"<code>Set</code>",
|
||
"<code>List</code>",
|
||
"<code>Map</code>",
|
||
"<code>Tuple</code>"
|
||
],
|
||
"ans": 2,
|
||
"exp": "<b>{}</b> 且含冒号键值对时创建 <b>Map</b>;无冒号的 <code>{1, 2, 3}</code> 是 Set;<code>[]</code> 是 List。Dart 没有 Tuple 类型。"
|
||
},
|
||
{
|
||
"id": 171,
|
||
"lv": 3,
|
||
"q": "<code>var map = {'a': 1}; map['b'] = 2;</code> 之后 map 的内容是?",
|
||
"opts": [
|
||
"<code>{'a': 1}</code>",
|
||
"<code>{'b': 2}</code>",
|
||
"报错",
|
||
"<code>{'a': 1, 'b': 2}</code>"
|
||
],
|
||
"ans": 3,
|
||
"exp": "<code>map[key] = value</code> 写入时,key 已存在则<b>更新值</b>,不存在则<b>新增条目</b>,所以得到 <code>{'a': 1, 'b': 2}</code>。"
|
||
},
|
||
{
|
||
"id": 172,
|
||
"lv": 3,
|
||
"q": "<code>['2024', '2025', '2026'].join('-')</code> 的结果是?",
|
||
"opts": [
|
||
"<code>'2024,2025,2026'</code>",
|
||
"报错",
|
||
"<code>'2024-2025-2026'</code>",
|
||
"<code>'202420252026'</code>"
|
||
],
|
||
"ans": 2,
|
||
"exp": "<b>join(分隔符)</b> 把列表元素按分隔符拼成一个字符串,得到 <code>2024-2025-2026</code>。注意不传参数时是<b>无分隔符</b>直接拼接。"
|
||
},
|
||
{
|
||
"id": 173,
|
||
"lv": 3,
|
||
"q": "从 <code>[1, 2, 3, 4]</code> 中挑出偶数(2、4),应调用哪个方法?",
|
||
"opts": [
|
||
"<code>map</code>",
|
||
"<code>reduce</code>",
|
||
"<code>addAll</code>",
|
||
"<code>where</code>"
|
||
],
|
||
"ans": 3,
|
||
"exp": "<b>where()</b> 按条件<b>过滤</b>:<code>[1,2,3,4].where((n) => n % 2 == 0)</code> 得到 2、4。map() 是变换每个元素,reduce() 是聚合,addAll() 是批量添加。"
|
||
},
|
||
{
|
||
"id": 174,
|
||
"lv": 3,
|
||
"q": "<code>var nums = [3, 1, 2]; nums.sort();</code> 排序后 nums 是?",
|
||
"opts": [
|
||
"<code>[3, 1, 2]</code>",
|
||
"<code>[1, 2, 3]</code>",
|
||
"报错",
|
||
"<code>[2, 3, 1]</code>"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<b>sort()</b> 原地<b>升序</b>排序,结果 <b>[1, 2, 3]</b>。注意它直接修改原列表并返回 void;要降序需传比较器:<code>sort((a, b) => b - a)</code>。"
|
||
},
|
||
{
|
||
"id": 175,
|
||
"lv": 3,
|
||
"q": "<code>[1, 2, 3].contains(5)</code> 返回?",
|
||
"opts": [
|
||
"<code>true</code>",
|
||
"<code>5</code>",
|
||
"<code>null</code>",
|
||
"<code>false</code>"
|
||
],
|
||
"ans": 3,
|
||
"exp": "<b>contains()</b> 判断是否包含指定元素,包含返回 true、否则 <b>false</b>。判断 Map 的键用 <code>containsKey</code>,判断值用 <code>containsValue</code>。"
|
||
},
|
||
{
|
||
"id": 176,
|
||
"lv": 4,
|
||
"q": "<code>class Point { Point(this.x, this.y); int x; int y; }</code> 中 this.x 的作用是?",
|
||
"opts": [
|
||
"创建私有变量",
|
||
"引用父类构造函数",
|
||
"把构造参数自动赋给同名成员变量",
|
||
"声明静态字段"
|
||
],
|
||
"ans": 2,
|
||
"exp": "构造参数写成 <b>this.x</b> 时,Dart 会把参数值<b>自动赋给同名成员变量</b>,省去手写 <code>this.x = x;</code> 的样板代码。"
|
||
},
|
||
{
|
||
"id": 177,
|
||
"lv": 4,
|
||
"q": "想给 Point 提供便捷构造 <code>Point.origin()</code>(x、y 初始化为 0),应该用?",
|
||
"opts": [
|
||
"静态方法",
|
||
"构造重载",
|
||
"默认构造函数",
|
||
"命名构造函数"
|
||
],
|
||
"ans": 3,
|
||
"exp": "<b>命名构造函数</b>:<code>Point.origin() : x = 0, y = 0;</code>,调用 <code>Point.origin()</code>。Dart 不支持构造重载,用命名构造区分多种初始化方式。"
|
||
},
|
||
{
|
||
"id": 178,
|
||
"lv": 4,
|
||
"q": "统计 Point 类一共创建了多少个实例,计数变量应声明为?",
|
||
"opts": [
|
||
"<code>final int count</code>",
|
||
"<code>static int count</code>",
|
||
"<code>int count</code>",
|
||
"<code>late int count</code>"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<b>static</b> 成员属于<b>类本身</b>、所有实例共享一份,在构造函数里 <code>count++</code> 即可统计,读取用 <code>Point.count</code>,不需要实例。"
|
||
},
|
||
{
|
||
"id": 179,
|
||
"lv": 4,
|
||
"q": "私有字段 _name 想对外<b>只读</b>(能读不能写),应该声明?",
|
||
"opts": [
|
||
"<code>void name() {}</code>",
|
||
"<code>static String name;</code>",
|
||
"<code>String get name => _name;</code>",
|
||
"<code>set String name;</code>"
|
||
],
|
||
"ans": 2,
|
||
"exp": "<b>getter</b> 提供只读访问:<code>String get name => _name;</code>,外部用 <code>p.name</code> 读取;需要可写时再补 <code>set name(String v)</code>。"
|
||
},
|
||
{
|
||
"id": 180,
|
||
"lv": 4,
|
||
"q": "<code>@override</code> 注解放在重写方法上的作用是?",
|
||
"opts": [
|
||
"调用父类方法",
|
||
"声明重写父类方法,签名不符会编译报错",
|
||
"创建新方法",
|
||
"删除父类方法"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<b>@override</b> 声明\"此方法重写了父类/接口方法\",签名不一致时<b>编译报错</b>,防止手滑写错。调用父类实现用 <code>super.xxx()</code>。"
|
||
},
|
||
{
|
||
"id": 181,
|
||
"lv": 4,
|
||
"q": "子类构造函数里显式调用父类构造函数,用哪个关键字?",
|
||
"opts": [
|
||
"<code>this</code>",
|
||
"<code>base</code>",
|
||
"<code>super</code>",
|
||
"<code>parent</code>"
|
||
],
|
||
"ans": 2,
|
||
"exp": "用 <b>super</b>:<code>Dog(String n) : super(n);</code>。父类有默认构造时可省略(自动调用);需要传参或指定父类命名构造时才显式写 super。"
|
||
},
|
||
{
|
||
"id": 182,
|
||
"lv": 5,
|
||
"q": "<code>String? s;</code>(可能为 null),直接写 <code>print(s.length)</code> 会?",
|
||
"opts": [
|
||
"输出 0",
|
||
"输出 null",
|
||
"编译报错:可空类型不能直接调用方法",
|
||
"正常运行"
|
||
],
|
||
"ans": 2,
|
||
"exp": "空安全下 <code>String?</code> 可能为 null,<b>不能直接调用方法</b>,编译期直接报错——这是空安全的核心价值:把空指针问题拦在编译期。需先判空,或用 <code>?</code> / <code>!</code>。"
|
||
},
|
||
{
|
||
"id": 183,
|
||
"lv": 5,
|
||
"q": "希望\"s 为 null 时整句返回 null,否则调用 length\",应该用?",
|
||
"opts": [
|
||
"<code>s.length</code>",
|
||
"<code>s?.length</code>",
|
||
"<code>s!.length</code>",
|
||
"<code>s ?? length</code>"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<b>?.</b> 安全调用:s 为 null 时结果为 null、不执行调用。常与 <code>??</code> 配合兜底:<code>s?.length ?? 0</code>。<code>s!.length</code> 是强制解包,s 为 null 时运行时报错。"
|
||
},
|
||
{
|
||
"id": 184,
|
||
"lv": 5,
|
||
"q": "<code>int? x = null; x ??= 10;</code> 的作用是?",
|
||
"opts": [
|
||
"把 x 强制转为非空",
|
||
"x 为 null 时才赋值为 10,否则保持原值",
|
||
"报错",
|
||
"x 永远等于 10"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<b>??=</b> 是\"若空则赋值\":x 为 null 时赋 10,若已有值则保持不变。等价于 <code>x = x ?? 10</code>,常用于给可空变量设置默认值。"
|
||
},
|
||
{
|
||
"id": 185,
|
||
"lv": 5,
|
||
"q": "执行 <code>throw FormatException('格式错误');</code> 会?",
|
||
"opts": [
|
||
"打印日志后继续执行",
|
||
"抛出异常,未被捕获则程序中断",
|
||
"返回 null",
|
||
"编译错误"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<b>throw</b> 主动抛出异常并中断当前执行,外层 <b>try-catch</b> 能接住就继续运行,否则异常冒泡导致程序崩溃。适合校验不通过时立即终止。"
|
||
},
|
||
{
|
||
"id": 186,
|
||
"lv": 5,
|
||
"q": "处理可能出错的代码,正确的结构是?",
|
||
"opts": [
|
||
"<code>catch { } try { }</code>",
|
||
"<code>if (error) { }</code>",
|
||
"<code>try { } catch (e) { } finally { }</code>",
|
||
"<code>except: { }</code>"
|
||
],
|
||
"ans": 2,
|
||
"exp": "<b>try-catch-finally</b>:try 放可能异常的代码,catch 捕获处理(可写 <code>on FormatException</code> 精确分类),finally 无论成败都会执行,适合释放资源。"
|
||
},
|
||
{
|
||
"id": 187,
|
||
"lv": 6,
|
||
"q": "定义星期、状态码这类<b>固定的一组取值</b>,应使用?",
|
||
"opts": [
|
||
"<code>typedef</code>",
|
||
"<code>enum</code>",
|
||
"<code>const</code> 列表",
|
||
"<code>abstract</code> 类"
|
||
],
|
||
"ans": 1,
|
||
"exp": "<b>enum</b> 枚举:<code>enum Status { pending, done, failed }</code>,用 <code>Status.done</code> 取值,配合 switch 模式匹配处理,比散落的字符串常量更类型安全。"
|
||
},
|
||
{
|
||
"id": 188,
|
||
"lv": 6,
|
||
"q": "写一个\"返回列表首个元素\"的通用函数,任意类型都能用,正确的签名是?",
|
||
"opts": [
|
||
"<code>String first(List<String> list)</code>",
|
||
"<code>void first(List list)</code>",
|
||
"<code><T> T first(List<T> list)</code>",
|
||
"函数不能带类型参数"
|
||
],
|
||
"ans": 2,
|
||
"exp": "<b>泛型函数</b>:<code><T> T first(List<T> list)</code>,T 是类型占位,调用时自动推断:<code>first([1, 2])</code> 返回 int,<code>first(['a'])</code> 返回 String,既通用又保留类型信息。"
|
||
},
|
||
{
|
||
"id": 189,
|
||
"lv": 6,
|
||
"q": "<code>typedef Compare = int Function(int a, int b);</code> 的作用是?",
|
||
"opts": [
|
||
"创建了一个新函数",
|
||
"声明一个类",
|
||
"定义枚举",
|
||
"给函数类型起别名"
|
||
],
|
||
"ans": 3,
|
||
"exp": "<b>typedef</b> 给函数类型起别名:之后 <code>Compare cmp;</code> 或作为参数类型 <code>void sort(Compare cmp)</code>,签名一目了然。Dart 2.13+ 还能给普通类型起别名。"
|
||
},
|
||
{
|
||
"id": 190,
|
||
"lv": 6,
|
||
"q": "<code>var (name, age) = ('张三', 18);</code> 之后 name 和 age 的值是?",
|
||
"opts": [
|
||
"name=18,age='张三'",
|
||
"name='张三',age=18",
|
||
"报错:不能解构",
|
||
"两者都是 null"
|
||
],
|
||
"ans": 1,
|
||
"exp": "这是 Dart 3 的<b>解构</b>:把 Record <code>('张三', 18)</code> 按位置拆开,name='张三'、age=18。函数返回 Record 时配合解构取值非常简洁。"
|
||
}
|
||
]
|
||
}
|
||
],
|
||
"nextSetId": 12,
|
||
"nextQId": 191
|
||
} |