第三章:Dart语言特性与异步编程
面试中Dart语言特性考察集中在空安全、Future/Stream、隔离区(Isolate)三大核心。本章提供三个高频问答卡片,结构化拆解回答路径与追问陷阱。
🎯 面试问答卡片 ①:空安全(Null Safety)
| 面试问题 | 请解释 Dart 的空安全机制,以及它是如何防止空指针异常的? |
| 面试官考察点 | ① 是否理解可空与非空类型的区别;② 对操作符 ?、!、??、?. 的掌握程度;③ 对迁移成本(旧代码空安全迁移)的认知。 |
| 回答框架 | 声明→操作→优势:先说明默认非空,用 ? 声明可空;再用 ??提供默认值、!断言非空;最后强调编译期检查消除运行时 NPE。 |
| 示例回答 | Dart 2.12+ 默认所有类型非空。可空类型加 ?(如 int? a)。使用 a ?? 0 提供默认值,a?.toString() 安全调用。编译器强制检查可空值使用,使空指针异常在运行前就被发现,提升稳定性。 |
| 可能追问 | ① late 关键字的使用场景和风险?② 如何对已有的非空安全依赖库做适配?③ 泛型中的空安全如何处理(如 List<int?> vs List<int>)? |
| 避坑提醒 | 不要滥用 !(强制解包),应优先使用 ?? 或 ?.。对于延迟初始化的场景,优先用 late 但需确保赋值前不被读取;否则仍会抛出 LateInitializationError。 |
🎯 面试问答卡片 ②:Future 与 Stream
| 面试问题 | 请比较 Dart 中 Future 和 Stream 的区别,并分别给出一个典型使用场景。 |
| 面试官考察点 | ① 是否理解异步单次 vs 多次事件;② 是否掌握 async/await 和 async*/yield 语法;③ 能否清晰描述 Stream 的订阅与取消。 |
| 回答框架 | 定义对比→代码示例→实际应用:Future 代表一个未来值(如网络请求),Stream 代表一个数据序列(如按钮点击事件)。 |
| 示例回答 | Future 返回单个异步结果,用 await 获取;Stream 可连续推送多个数据,用 await for 遍历或 .listen() 订阅。例如 Future 用于 HTTP 请求,Stream 用于监听文件下载进度或 WebSocket 消息。 |
| 可能追问 | ① Stream 的 broadcast 与单订阅的区别?② StreamSubscription 如何正确取消防止内存泄漏?③ 如何将 Stream 转换为 Future(使用 .first、.toList())? |
| 避坑提醒 | 单订阅 Stream 只能被 listen 一次,否则抛异常;务必在 dispose 中调用 cancel()。避免在 Stream 回调中做耗时操作,会阻塞事件循环。 |
🎯 面试问答卡片 ③:隔离区(Isolate)与并发模式
| 面试问题 | 如何利用 Dart 的 Isolate 实现并发?与普通 async/await 有何本质不同? |
| 面试官考察点 | ① 是否理解隔离区拥有独立内存和事件循环;② 是否知道 Isolate.spawn() 和 compute() 的使用方法;③ 能否对比 async/await(单线程协作式并发)与 Isolate(独立线程并行)的适用场景。 |
| 回答框架 | 原理区别→通信方式→实际选择:async/await 仍在一个 Isolate 内避免阻塞,Isolate 则是真正的并行,需通过消息传递交换数据。 |
| 示例回答 | async/await 适合 I/O 等待(如网络请求),不会创建新线程;Isolate 通过 Isolate.spawn() 创建独立 Worker,用 SendPort/ReceivePort 通信,适合 CPU 密集型任务(如图片压缩)。Flutter 中常用 compute() 快速创建隔离区。 |
| 可能追问 | ① 多个 Isolate 如何共享状态?② 如何关闭一个隔离区?③ compute() 的参数限制是什么? |
| 避坑提醒 | 不要滥用 Isolate,启动和通信有开销。多次短任务使用 compute() 会反复创建销毁;长时间 Worker 建议复用隔离区。传递参数必须可拷贝(基本类型、列表、Map),不能传递闭包或 Flutter 对象。 |
💡 面试加分项:在回答 Isolate 相关问题时,主动提及 FlutterError.onError 与隔离区异常处理,以及如何通过 IsolateNameServer 实现隔离区发现。展现工程化深度。