一、变量与类型
1.1 变量声明
Dart 提供了多种变量声明方式,每种都有不同的用途和语义。理解它们的区别是写出高质量 Dart 代码的基础。
// var - 类型自动推断,可重新赋值 var name = 'Flutter'; // 推断为 String name = 'Dart'; // ✅ 可以重新赋值 // name = 123; // ❌ 不能改变类型 // final - 运行时常量,只能赋值一次 final createdAt = DateTime.now(); // 运行时确定值 final String title = '学习Dart'; // 可以显式指定类型 // const - 编译时常量,必须在编译期确定 const pi = 3.14159; // 编译时就确定的值 const maxItems = 100; // 整数常量 // const now = DateTime.now(); // ❌ 运行时值不能用 const // late - 延迟初始化 late String description; // 稍后初始化 late final String config = loadConfig(); // 懒加载,首次访问时才执行
提示:优先使用
final,只有需要重新赋值时才用 var。const 用于编译时就能确定的值,如配置常量。late 常用于需要延迟初始化或在构造函数体中初始化的场景。
1.2 基本数据类型
Dart 是强类型语言,所有变量都有类型。以下是最常用的内置类型:
// 数字类型 int age = 25; // 整数 double price = 19.99; // 浮点数 num value = 42; // int 或 double 的父类型 // 字符串 String greeting = 'Hello Dart'; String multiLine = ''' 这是一个 多行字符串 '''; String interpolation = '年龄是 $age, 明年 ${age + 1}'; // 布尔值 bool isActive = true; // 动态类型 - 慎用! dynamic anything = 'text'; anything = 42; // ✅ dynamic 可以改变类型 anything.noSuchMethod(); // 编译通过,运行时报错 // Object - 所有类的基类 Object obj = 'text'; // obj.length; // ❌ 编译错误,Object 没有 length // 类型转换 int parsed = int.parse('42'); double d = 42.toDouble(); String s = 42.toString();
1.3 空安全(Null Safety)
Dart 的空安全是其类型系统的核心特性,帮助你在编译期捕获空引用错误。
// 默认不可为 null String name = 'Dart'; // name = null; // ❌ 编译错误 // ? 声明可空类型 String? nickname; // 默认值为 null print(nickname); // 输出: null // ! 断言非空(确定不为 null 时使用) String sure = nickname!; // 如果 nickname 为 null 会抛异常 // ?? 空合并运算符 String display = nickname ?? '匿名用户'; // nickname 为 null 时用默认值 // ??= 空值赋值 nickname ??= '默认昵称'; // 仅在 null 时赋值 // ?. 安全调用运算符 int? length = nickname?.length; // nickname 为 null 时返回 null // 实际应用示例 String getUserName(Map<String, dynamic> json) { return json['name']?.toString() ?? '未知用户'; } // 类型提升(Flow Analysis) void process(String? input) { if (input == null) return; // 此处 input 自动提升为 String(非空) print(input.length); // ✅ 安全访问 }
最佳实践:尽量避免使用
! 操作符,它会跳过空安全检查。优先使用 ?? 提供默认值,或使用 if 判断让编译器自动进行类型提升。
二、集合类型
2.1 List(列表)
List 是 Dart 中最常用的有序集合,类似于其他语言的数组。
// 创建列表 var fruits = ['苹果', '香蕉', '橙子']; // 类型推断为 List<String> List<int> numbers = [1, 2, 3, 4, 5]; var empty = <String>[]; // 空的类型列表 // 常用操作 fruits.add('葡萄'); // 添加元素 fruits.addAll(['芒果', '荔枝']); // 添加多个 fruits.insert(0, '西瓜'); // 在指定位置插入 fruits.remove('香蕉'); // 删除元素 fruits.removeAt(0); // 删除指定索引 // 函数式操作(非常重要!Flutter 中大量使用) var lengths = fruits.map((f) => f.length).toList(); var longFruits = fruits.where((f) => f.length > 1).toList(); var hasApple = fruits.any((f) => f == '苹果'); var allLong = fruits.every((f) => f.length > 0); var total = numbers.reduce((a, b) => a + b); // 求和 var first = fruits.firstWhere((f) => f.startsWith('苹')); // 不可变列表 final fixed = List.unmodifiable([1, 2, 3]); const constList = [1, 2, 3]; // 编译时常量列表
2.2 Set(集合)与 Map(映射)
// Set - 无序不重复集合 var tags = {'Flutter', 'Dart', 'Mobile'}; tags.add('Flutter'); // 不会重复添加 tags.add('Web'); // Set 运算 var a = {1, 2, 3}; var b = {2, 3, 4}; print(a.union(b)); // {1, 2, 3, 4} 并集 print(a.intersection(b)); // {2, 3} 交集 print(a.difference(b)); // {1} 差集 // Map - 键值对 var user = { 'name': '张三', 'age': 25, 'email': 'zhang@example.com', }; // Map 操作 user['phone'] = '13800138000'; // 添加/修改 user.remove('email'); // 删除 var hasName = user.containsKey('name'); // 遍历 Map user.forEach((key, value) { print('$key: $value'); }); // Map 转换 var upperKeys = user.map((k, v) => MapEntry(k.toUpperCase(), v));
2.3 展开运算符与集合操作
// 展开运算符 ... var base = [1, 2, 3]; var extended = [0, ...base, 4]; // [0, 1, 2, 3, 4] // 空感知展开运算符 ...? List<int>? maybeNull; var safe = [0, ...?maybeNull]; // [0],不会报错 // 集合 if(在 Flutter UI 构建中非常实用) var isLoggedIn = true; var menu = [ '首页', '发现', if (isLoggedIn) '个人中心', // 条件添加 if (!isLoggedIn) '登录', ]; // 集合 for var items = [1, 2, 3]; var doubled = [ for (var i in items) i * 2, // [2, 4, 6] ]; // 组合使用 - Flutter 中的典型场景 var widgets = [ 'Header', for (var item in items) 'Item: $item', if (items.length > 2) '查看更多...', ];
注意:集合 if 和集合 for 在 Flutter 的 Widget 树构建中大量使用,比如动态生成列表项或条件显示某些 Widget。务必掌握这些语法。
三、函数
3.1 函数定义与箭头函数
Dart 中函数是一等对象,可以赋值给变量、作为参数传递、从函数返回。
// 标准函数定义 int add(int a, int b) { return a + b; } // 箭头函数(函数体只有一个表达式时使用) int multiply(int a, int b) => a * b; // 函数作为变量 var greet = (String name) => '你好,$name!'; print(greet('Flutter')); // 你好,Flutter! // 函数作为参数 void execute(int Function(int, int) operation, int x, int y) { print('结果: ${operation(x, y)}'); } execute(add, 3, 4); // 结果: 7 execute(multiply, 3, 4); // 结果: 12
3.2 参数类型
// 必需位置参数 String fullName(String first, String last) { return '$first $last'; } // 可选位置参数 - 用 [] 包裹 String introduce(String name, [int? age, String city = '未知']) { var result = '我是$name'; if (age != null) result += ',$age岁'; result += ',来自$city'; return result; } introduce('张三'); // 我是张三,来自未知 introduce('李四', 25, '北京'); // 我是李四,25岁,来自北京 // 命名参数 - 用 {} 包裹(Flutter 中最常用!) void createUser({ required String name, // 必需命名参数 int age = 0, // 带默认值的命名参数 String? email, // 可选命名参数 }) { print('创建用户: $name, $age, $email'); } // 调用时参数名清晰可读 createUser(name: '王五', age: 30, email: 'wang@test.com'); createUser(name: '赵六'); // age 默认 0, email 为 null
3.3 闭包与 typedef
// 闭包 - 函数可以捕获外部变量 Function makeCounter() { int count = 0; return () { count++; return count; }; } var counter = makeCounter(); print(counter()); // 1 print(counter()); // 2 print(counter()); // 3 // 闭包在 Flutter 中的实际应用 List<Function()> buildCallbacks(List<String> items) { return items.map((item) { return () => print('点击了: $item'); }).toList(); } // typedef - 定义函数类型别名 typedef Comparator<T> = int Function(T a, T b); typedef OnChanged<T> = void Function(T value); // 使用 typedef void sortList(List<int> list, Comparator<int> compare) { list.sort(compare); } sortList([3, 1, 2], (a, b) => a - b); // 升序排列
Flutter 重点:Flutter 中的 Widget 构造函数大量使用命名参数。回调函数(如
onPressed、onChanged)是闭包的典型应用。建议牢记命名参数的 required 语法。
四、控制流
4.1 条件与循环
// if-else var score = 85; if (score >= 90) { print('优秀'); } else if (score >= 60) { print('及格'); } else { print('不及格'); } // 三元表达式 var status = score >= 60 ? '通过' : '未通过'; // switch 语句 var command = 'open'; switch (command) { case 'open': print('打开'); break; case 'close': print('关闭'); break; default: print('未知命令'); } // for 循环 for (var i = 0; i < 5; i++) { print('索引: $i'); } // for-in 遍历 var colors = ['红', '绿', '蓝']; for (var color in colors) { print(color); } // while 和 do-while var n = 5; while (n > 0) { print(n--); }
4.2 Dart 3 模式匹配(Pattern Matching)
Dart 3 引入了强大的模式匹配功能,让代码更简洁、更安全。
// switch 表达式(Dart 3 新语法) String describe(int score) => switch (score) { >= 90 => '优秀', >= 80 => '良好', >= 60 => '及格', _ => '不及格', }; // 解构赋值 var point = (3, 4); // Record var (x, y) = point; // 解构: x=3, y=4 // 命名字段解构 var user = (name: '张三', age: 25); var (:name, :age) = user; // name='张三', age=25 // List 解构 var [first, second, ...rest] = [1, 2, 3, 4, 5]; // first=1, second=2, rest=[3,4,5] // Map 解构 var {'name': userName, 'age': userAge} = {'name': '李四', 'age': 30}; // if-case 模式匹配 var data = {'type': 'success', 'value': 42}; if (data case {'type': 'success', 'value': int v}) { print('成功,值为: $v'); // v 自动绑定且类型为 int } // switch 匹配复杂类型 void handleResponse(Object response) { switch (response) { case String s: print('字符串: $s'); case int n when n > 0: print('正整数: $n'); case [int x, int y]: print('坐标: ($x, $y)'); case {'error': String msg}: print('错误: $msg'); default: print('未知类型'); } }
Dart 3 提示:模式匹配是 Dart 3 最重要的新特性之一。switch 表达式(用
=>)比传统 switch 语句更简洁,且编译器会检查是否覆盖了所有情况。
五、面向对象
5.1 类与构造函数
Dart 是纯面向对象语言,所有值都是对象。类是组织代码的核心方式。
class User { // 实例属性 final String name; int age; String? _email; // _ 开头表示私有 // 默认构造函数 - 使用语法糖简化赋值 User(this.name, this.age, [this._email]); // 命名构造函数 User.guest() : name = '访客', age = 0; User.fromJson(Map<String, dynamic> json) : name = json['name'] as String, age = json['age'] as int; // getter 和 setter String? get email => _email; set email(String? value) { if (value != null && value.contains('@')) { _email = value; } } // 计算属性 bool get isAdult => age >= 18; // 方法 String greet() => '大家好,我是$name'; // 重写 toString @override String toString() => 'User($name, $age)'; } // 使用 var user = User('张三', 25, 'zhang@test.com'); var guest = User.guest(); var jsonUser = User.fromJson({'name': '李四', 'age': 30});
5.2 工厂构造函数与 const 构造函数
// 工厂构造函数 - 可以返回缓存实例或子类 class Logger { static final Map<String, Logger> _cache = {}; final String name; // 私有构造函数 Logger._internal(this.name); // 工厂构造函数 - 实现单例模式 factory Logger(String name) { return _cache.putIfAbsent( name, () => Logger._internal(name), ); } void log(String msg) => print('[$name] $msg'); } // 两个变量指向同一个实例 var log1 = Logger('APP'); var log2 = Logger('APP'); print(identical(log1, log2)); // true // const 构造函数 - 编译时常量对象 class Point { final double x; final double y; const Point(this.x, this.y); // const 构造函数中所有字段必须是 final double get distance => (x * x + y * y); } // const 对象在编译时创建,相同值共享实例 const p1 = Point(1, 2); const p2 = Point(1, 2); print(identical(p1, p2)); // true,共享同一实例
5.3 继承与抽象类
// 抽象类 - 不能直接实例化 abstract class Shape { // 抽象方法 - 子类必须实现 double area(); double perimeter(); // 普通方法 - 子类可以继承 String describe() => '面积: ${area().toStringAsFixed(2)}'; } class Circle extends Shape { final double radius; Circle(this.radius); @override double area() => 3.14159 * radius * radius; @override double perimeter() => 2 * 3.14159 * radius; } class Rectangle extends Shape { final double width, height; Rectangle(this.width, this.height); @override double area() => width * height; @override double perimeter() => 2 * (width + height); }
5.4 Mixin 与扩展方法
// Mixin - 代码复用机制(不同于继承) mixin Printable { void printInfo() => print(toString()); } mixin Serializable { Map<String, dynamic> toJson(); String serialize() => toJson().toString(); } // 使用 with 关键字混入 class Product with Printable, Serializable { final String name; final double price; Product(this.name, this.price); @override Map<String, dynamic> toJson() => { 'name': name, 'price': price, }; @override String toString() => '$name (¥$price)'; } // 扩展方法 - 给现有类添加功能 extension StringX on String { // 检查是否为有效邮箱 bool get isEmail => RegExp(r'^[\w-\.]+@[\w-]+\.\w+$').hasMatch(this); // 首字母大写 String get capitalize => isEmpty ? this : '${this[0].toUpperCase()}${substring(1)}'; } // 使用扩展方法 print('test@mail.com'.isEmail); // true print('hello'.capitalize); // Hello // 增强枚举(Dart 2.17+) enum Priority { low(1, '低'), medium(2, '中'), high(3, '高'), urgent(4, '紧急'); final int level; final String label; const Priority(this.level, this.label); // 枚举可以有方法和 getter bool get isUrgent => level >= 3; @override String toString() => 'Priority.$name($label)'; } var p = Priority.high; print(p.label); // 高 print(p.isUrgent); // true
注意:Mixin 是 Dart 中非常灵活的代码复用方式,Flutter 框架中大量使用(如
TickerProviderStateMixin)。扩展方法可以让你给任何类添加方法,非常适合编写工具方法。增强枚举让枚举类型更加强大实用。
六、泛型
6.1 泛型类与泛型函数
泛型允许你编写类型安全且可复用的代码,避免重复编写类似逻辑。
// 泛型类 - 通用的结果包装器 class Result<T> { final T? data; final String? error; final bool isSuccess; Result.success(this.data) : error = null, isSuccess = true; Result.failure(this.error) : data = null, isSuccess = false; // 泛型方法 - 转换包装的数据类型 Result<R> map<R>(R Function(T) transform) { if (isSuccess && data != null) { return Result.success(transform(data as T)); } return Result.failure(error); } } // 使用泛型类 var result = Result<int>.success(42); var strResult = result.map((n) => '数字是 $n'); // Result<String> var error = Result<String>.failure('网络错误'); // 泛型函数 T firstOrDefault<T>(List<T> list, T defaultValue) { return list.isNotEmpty ? list.first : defaultValue; } var num1 = firstOrDefault([1, 2, 3], 0); // int 类型 var str1 = firstOrDefault(<String>[], '空'); // String 类型
6.2 类型约束
// 使用 extends 约束泛型类型 class NumberList<T extends num> { final List<T> _items = []; void add(T value) => _items.add(value); // 因为 T 约束为 num,可以安全调用 num 的方法 T get max => _items.reduce((a, b) => (a > b ? a : b) as T); double get average { if (_items.isEmpty) return 0; var sum = _items.fold<num>(0, (prev, e) => prev + e); return sum / _items.length; } } var intList = NumberList<int>(); intList.add(10); intList.add(20); print(intList.average); // 15.0 // 泛型实际应用 - 仓库模式 abstract class Repository<T> { Future<List<T>> getAll(); Future<T?> getById(String id); Future<void> save(T entity); Future<void> delete(String id); } // 具体实现 class UserRepository implements Repository<User> { @override Future<List<User>> getAll() async { // 从数据库或 API 获取用户列表 return []; } // ... 其他方法 @override Future<User?> getById(String id) async => null; @override Future<void> save(User entity) async {} @override Future<void> delete(String id) async {} }
提示:泛型在 Flutter 中无处不在。
ListView.builder、FutureBuilder<T>、ValueNotifier<T> 等都依赖泛型。掌握泛型是理解 Flutter 源码的前提。
七、异步编程
7.1 Future 与 async/await
异步编程是 Dart 的核心特性之一。网络请求、文件读写、数据库操作等都是异步的。
// 返回 Future 的函数 Future<String> fetchUserName(int userId) async { // 模拟网络请求延迟 await Future.delayed(Duration(seconds: 2)); return '用户_$userId'; } // 使用 async/await Future<void> loadData() async { try { var name = await fetchUserName(1); print('获取到: $name'); } catch (e) { print('出错了: $e'); } finally { print('加载完成'); } } // 并行执行多个异步任务 Future<void> loadAll() async { // 同时发起多个请求,等待全部完成 var results = await Future.wait([ fetchUserName(1), fetchUserName(2), fetchUserName(3), ]); print(results); // [用户_1, 用户_2, 用户_3] } // Future 链式调用 fetchUserName(1) .then((name) => print('用户: $name')) .catchError((e) => print('错误: $e')) .whenComplete(() => print('完成')); // 带超时的 Future var name = await fetchUserName(1) .timeout(Duration(seconds: 5), onTimeout: () => '超时默认值');
7.2 Stream(数据流)
// 创建 Stream Stream<int> countStream(int max) async* { for (var i = 1; i <= max; i++) { await Future.delayed(Duration(seconds: 1)); yield i; // 逐个产出值 } } // 监听 Stream Future<void> listenToCount() async { // 方式1: await for await for (var count in countStream(5)) { print('计数: $count'); } // 方式2: listen countStream(3).listen( (data) => print('数据: $data'), onError: (e) => print('错误: $e'), onDone: () => print('完成'), ); } // StreamController - 手动控制 Stream import 'dart:async'; class EventBus { final _controller = StreamController<String>.broadcast(); Stream<String> get events => _controller.stream; void emit(String event) => _controller.add(event); void dispose() => _controller.close(); } // Stream 转换操作 countStream(10) .where((n) => n.isEven) // 过滤偶数 .map((n) => '偶数: $n') // 转换 .take(3) // 只取前3个 .listen(print);
7.3 Isolate 与 compute()
import 'dart:isolate'; import 'package:flutter/foundation.dart'; // compute() - Flutter 提供的简便方式在隔离线程中执行计算 // 适用于耗时的纯计算任务,避免阻塞 UI 线程 // 必须是顶层函数或静态方法 int heavyComputation(int n) { // 模拟耗时计算(如大数据解析、图片处理) var sum = 0; for (var i = 0; i < n; i++) { sum += i; } return sum; } // 使用 compute Future<void> runHeavyTask() async { // 在独立 Isolate 中执行,不会卡 UI var result = await compute(heavyComputation, 1000000); print('计算结果: $result'); } // 直接使用 Isolate(更灵活但更复杂) Future<void> useIsolate() async { // Dart 2.19+ Isolate.run 简化写法 var result = await Isolate.run(() { // 这段代码在独立 Isolate 中执行 return heavyComputation(1000000); }); print('Isolate 结果: $result'); } // JSON 解析实际示例 List<Map<String, dynamic>> parseJsonList(String jsonStr) { // 假设这是大量 JSON 数据的解析 import 'dart:convert'; return (jsonDecode(jsonStr) as List).cast(); } // 在 Isolate 中解析大 JSON Future<List<Map<String, dynamic>>> fetchAndParse() async { var jsonStr = await fetchFromNetwork(); // 网络请求 return await compute(parseJsonList, jsonStr); // 隔离线程解析 }
重要:在 Flutter 中,UI 运行在主 Isolate 上。耗时超过 16ms 的计算(如大 JSON 解析、图片处理)应该放在
compute() 或单独的 Isolate 中执行,否则会导致界面卡顿。async/await 不会创建新线程,它只是异步等待。
八、高级特性(Dart 3)
8.1 Records(记录)
Records 是 Dart 3 引入的轻量级不可变数据结构,适合返回多个值或临时数据组合。
// 位置 Record (int, String) getUserInfo() { return (25, '张三'); } var info = getUserInfo(); print(info.$1); // 25 (位置从 $1 开始) print(info.$2); // 张三 // 命名 Record ({String name, int age, String email}) getUser() { return (name: '李四', age: 30, email: 'li@test.com'); } var user = getUser(); print(user.name); // 李四 print(user.age); // 30 // 混合 Record(位置 + 命名) (int, int, {String label}) point = (10, 20, label: '原点'); // Record 解构 var (age, name) = getUserInfo(); // age=25, name='张三' // Record 的相等性比较(按值比较) var r1 = (1, 'a'); var r2 = (1, 'a'); print(r1 == r2); // true(值相等即相等) // 实际应用 - 替代简单的数据类 Future<({List<String> items, bool hasMore})> fetchPage(int page) async { // 一次返回多个相关的值 return (items: ['项目1', '项目2'], hasMore: true); }
8.2 Sealed 类与穷尽匹配
// sealed 类 - 限制子类范围,支持穷尽匹配 sealed class AppState {} class Loading extends AppState {} class Loaded extends AppState { final List<String> data; Loaded(this.data); } class Error extends AppState { final String message; Error(this.message); } // 穷尽匹配 - 编译器确保处理所有情况 String renderState(AppState state) => switch (state) { Loading() => '加载中...', Loaded(data: var items) => '共 ${items.length} 条数据', Error(message: var msg) => '错误: $msg', // 不需要 default!编译器知道已覆盖所有情况 }; // 状态管理实际应用 sealed class NetworkResult<T> {} class Success<T> extends NetworkResult<T> { final T data; Success(this.data); } class Failure<T> extends NetworkResult<T> { final String error; final int? statusCode; Failure(this.error, [this.statusCode]); } // 在 Widget 中使用 Widget buildContent(NetworkResult<User> result) => switch (result) { Success(data: var user) => Text('欢迎, ${user.name}'), Failure(error: var msg, statusCode: 404) => Text('未找到: $msg'), Failure(error: var msg) => Text('错误: $msg'), };
8.3 更多模式匹配技巧
// 对象模式 - 匹配对象的属性 class Rect { final double width, height; Rect(this.width, this.height); double get area => width * height; } String classifyRect(Rect r) => switch (r) { Rect(width: var w, height: var h) when w == h => '正方形 ($w x $h)', Rect(area: > 100) => '大矩形', Rect(area: > 50) => '中矩形', _ => '小矩形', }; // guard 子句 when String checkAge(Object value) => switch (value) { int n when n < 0 => '无效年龄', int n when n < 18 => '未成年', int n when n < 60 => '成年人', int _ => '老年人', _ => '不是数字', }; // 逻辑模式组合 String describeNumber(int n) => switch (n) { 0 => '零', 1 || 2 || 3 => '小数字', // 或模式 >= 4 && <= 10 => '中等数字', // 且模式 > 10 => '大数字', _ => '负数', };
进阶提示:Sealed 类 + 模式匹配是 Dart 3 中管理应用状态的最佳实践。编译器会强制你处理所有可能的状态,大大减少遗漏导致的 bug。这在 Flutter 状态管理中特别有用。
九、实践练习
练习一:数据模型与 JSON 序列化
实现一个完整的用户数据模型,包含 JSON 序列化、数据验证和工厂构造函数。
// 练习:补全以下代码并运行测试 class UserModel { final String id; final String name; final String email; final int age; final List<String> tags; const UserModel({ required this.id, required this.name, required this.email, required this.age, this.tags = const [], }); // 工厂构造:从 JSON 创建 factory UserModel.fromJson(Map<String, dynamic> json) { return UserModel( id: json['id'] as String, name: json['name'] as String, email: json['email'] as String, age: json['age'] as int, tags: (json['tags'] as List?) ?.map((e) => e as String).toList() ?? [], ); } // 转换为 JSON Map<String, dynamic> toJson() => { 'id': id, 'name': name, 'email': email, 'age': age, 'tags': tags, }; // copyWith - 不可变对象的更新模式 UserModel copyWith({ String? name, String? email, int? age, List<String>? tags, }) { return UserModel( id: id, name: name ?? this.name, email: email ?? this.email, age: age ?? this.age, tags: tags ?? this.tags, ); } // 数据验证 bool get isValid => name.isNotEmpty && email.contains('@') && age > 0 && age < 150; @override String toString() => 'UserModel($name, $email)'; } // 测试代码 void main() { var user = UserModel.fromJson({ 'id': '001', 'name': '张三', 'email': 'zhang@test.com', 'age': 25, 'tags': ['Flutter', 'Dart'], }); print(user.isValid); // true print(user.toJson()); // JSON Map print(user.copyWith(name: '李四').name); // 李四 }
练习二:异步任务管理器
实现一个简单的异步任务管理器,支持并发控制和结果收集。
// 练习:实现一个带并发控制的任务执行器 class TaskRunner<T> { final int maxConcurrent; final List<Future<T> Function()> _tasks = []; final List<T> _results = []; int _running = 0; TaskRunner({this.maxConcurrent = 3}); // 添加任务 void addTask(Future<T> Function() task) { _tasks.add(task); } // 执行所有任务(带并发控制) Future<List<T>> runAll() async { final completer = Completer<List<T>>(); var index = 0; void runNext() async { if (index >= _tasks.length) { if (_running == 0) { completer.complete(_results); } return; } final currentIndex = index++; _running++; try { var result = await _tasks[currentIndex](); _results.add(result); } catch (e) { print('任务 $currentIndex 失败: $e'); } finally { _running--; runNext(); // 完成一个就启动下一个 } } // 启动初始批次 var initial = _tasks.length < maxConcurrent ? _tasks.length : maxConcurrent; for (var i = 0; i < initial; i++) { runNext(); } if (_tasks.isEmpty) return []; return completer.future; } } // 使用示例 void main() async { var runner = TaskRunner<String>(maxConcurrent: 2); for (var i = 0; i < 5; i++) { runner.addTask(() async { await Future.delayed(Duration(seconds: 1)); return '任务$i完成'; }); } var results = await runner.runAll(); print(results); // [任务0完成, 任务1完成, ...] }
练习三:Sealed 类实现状态机
使用 Dart 3 的 Sealed 类实现一个购物车状态管理。
// 练习:使用 sealed 类管理购物车状态 sealed class CartState {} class CartEmpty extends CartState {} class CartLoading extends CartState {} class CartLoaded extends CartState { final List<CartItem> items; CartLoaded(this.items); double get totalPrice => items.fold(0, (sum, item) => sum + item.price * item.quantity); int get itemCount => items.fold(0, (sum, item) => sum + item.quantity); } class CartError extends CartState { final String message; CartError(this.message); } // 购物车项目 class CartItem { final String name; final double price; final int quantity; const CartItem({ required this.name, required this.price, this.quantity = 1, }); CartItem copyWith({int? quantity}) => CartItem(name: name, price: price, quantity: quantity ?? this.quantity); } // 渲染购物车状态(穷尽匹配) String renderCart(CartState state) => switch (state) { CartEmpty() => '🛒 购物车为空,去逛逛吧!', CartLoading() => '⏳ 加载中...', CartLoaded(items: []) => '🛒 购物车为空', CartLoaded(items: var items, totalPrice: var total) => '🛍 ${items.length} 种商品,合计: ¥${total.toStringAsFixed(2)}', CartError(message: var msg) => '❌ $msg', }; // 测试 void main() { var states = [ CartEmpty(), CartLoading(), CartLoaded([ CartItem(name: 'Flutter 实战', price: 79.0, quantity: 2), CartItem(name: 'Dart 编程', price: 59.0), ]), CartError('网络连接失败'), ]; for (var state in states) { print(renderCart(state)); } // 输出: // 🛒 购物车为空,去逛逛吧! // ⏳ 加载中... // 🛍 2 种商品,合计: ¥217.00 // ❌ 网络连接失败 }
练习建议:建议在 DartPad 上运行这些代码。尝试修改和扩展功能,比如给 UserModel 添加密码验证、给 TaskRunner 添加重试机制、给购物车添加优惠券功能等。