> ## Content Index
> Fetch the complete content index at: https://blog.vercanti.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Dart 入门
- URL: https://blog.vercanti.com/dart-ru-men/
- Published: 2026-08-28T14:35:42.000Z
- Updated: 2026-08-28T14:59:25.000Z
- Description: 最后更新：2026-03-05 本文面向已有 Python 或 JavaScript 基础、想通过 Dart 进入 Flutter 开发的初学者。Dart 是谷歌开发的强类型、面向对象的编译型语言，是 Flutter入门(/flutter-ru-men/) 的唯一开发语言。 1. 基础语法(#%E5%9F%BA%E7%A1%80%E8%AF%AD%E6%B3%95) 2. 流程控制(#%E6%B5%81%E7%A8%8B%E6%8E%A7%E5%88%B6) 3. 函数(#%E5%87%BD%E6%95%B0) 4. 面向对象(#%E9%9D%A2%E5
- Author: yellowdog
- Tags: 移动开发

最后更新：2026-03-05

> 官方文档：<https://dart.dev/guides>  
> 适用版本：Dart 3.x（2026-05-07 核实）

本文面向已有 Python 或 JavaScript 基础、想通过 Dart 进入 Flutter 开发的初学者。Dart 是谷歌开发的强类型、面向对象的编译型语言，是 [Flutter入门](https://blog.vercanti.com/flutter-ru-men/) 的唯一开发语言。

---

## 目录

1. [基础语法](#%E5%9F%BA%E7%A1%80%E8%AF%AD%E6%B3%95)
2. [流程控制](#%E6%B5%81%E7%A8%8B%E6%8E%A7%E5%88%B6)
3. [函数](#%E5%87%BD%E6%95%B0)
4. [面向对象](#%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1)
5. [异步编程](#%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B)
6. [库与包](#%E5%BA%93%E4%B8%8E%E5%8C%85)
7. [Dart 3 新特性](#dart-3-%E6%96%B0%E7%89%B9%E6%80%A7)
8. [综合实战：命令行 Todo 应用](#%E7%BB%BC%E5%90%88%E5%AE%9E%E6%88%98%EF%BC%9A%E5%91%BD%E4%BB%A4%E8%A1%8C-todo-%E5%BA%94%E7%94%A8)

---

## 基础语法

### 变量与类型

Dart 是强类型语言，但支持类型推断。与 Python 的动态类型和 JavaScript 的弱类型不同，Dart 在编译期就能捕获类型错误。

```dart
// var：类型推断，一旦赋值类型固定
var name = 'Alice';      // 推断为 String
var age = 25;            // 推断为 int
// name = 42;            // 编译错误：不能把 int 赋给 String

// 显式类型声明
String city = 'Beijing';
int count = 100;
double price = 9.99;

// final：运行时常量，只能赋值一次（类似 JavaScript 的 const）
final greeting = 'Hello';
// greeting = 'Hi';      // 错误：final 变量不能重新赋值

// const：编译期常量，值必须在编译时已知
const pi = 3.14159;
const maxCount = 100;

// Python 对比：Python 没有 final/const，所有变量都可重新赋值
// JS 对比：JS 的 let 对应 var，JS 的 const 类似 Dart 的 final（运行时）

```

`var` / `final` / `const` 区别对比：

| 关键字       | 类型推断  | 可重新赋值 | 赋值时机 |
| --------- | ----- | ----- | ---- |
| var       | 是     | 是     | 任何时候 |
| final     | 是     | 否（一次） | 运行时  |
| const     | 是     | 否     | 编译期  |
| Type name | 否（显式） | 是     | 任何时候 |

### 内置类型

```dart
// int：整数，无大小限制（Web 端有精度限制）
int x = 42;
int hex = 0xFF;

// double：64位浮点数
double y = 3.14;
double scientific = 1.5e2;   // 150.0

// num：int 和 double 的父类
num n = 10;
n = 3.14;   // 合法

// String：Unicode 字符串，单引号双引号均可
String s1 = 'hello';
String s2 = "world";

// bool：只有 true 和 false，不像 JS 存在隐式真值转换
bool flag = true;
// if (1) {}    // Dart 编译错误，JS 中合法

// dynamic：放弃类型检查，类似 Python 动态类型（不推荐滥用）
dynamic anything = 42;
anything = 'now a string';   // 合法

// Object：所有 Dart 类的基类（可空版本是 Object?）
Object obj = 'hello';

```

### 空安全（Null Safety）

Dart 2.12 引入空安全，是 Dart 最重要的特性之一。默认情况下，变量不能为 null，必须显式声明可空类型。

```dart
// 非空类型：不能赋值为 null
String name = 'Alice';
// name = null;   // 编译错误

// 可空类型：在类型后加 ?
String? nullableName = null;    // 合法
nullableName = 'Bob';           // 也合法

// ? 条件成员访问：若为 null 则返回 null，不抛异常
// 类似 JavaScript 的 ?.（可选链）
int? length = nullableName?.length;

// ?? 空合并运算符：左侧为 null 时返回右侧
// 类似 JavaScript 的 ?? 和 Python 的 or（但更严格）
String displayName = nullableName ?? '匿名用户';

// ??= 空合并赋值：仅当变量为 null 时赋值
String? user;
user ??= '默认用户';   // user 现在是 '默认用户'

// ! 非空断言：告诉编译器"我确信这里不是 null"
// 若实际为 null 则运行时抛出 Null check operator used on a null value
String definitelyNotNull = nullableName!;

// late：延迟初始化，声明时不赋值，使用前必须赋值
late String lateVar;
// print(lateVar);   // 运行时错误：LateInitializationError
lateVar = '现在初始化了';
print(lateVar);       // 正常

```

空安全操作符汇总：

| 操作符 | 含义     | 示例             |
| --- | ------ | -------------- |
| ?   | 声明可空类型 | String? name   |
| ?.  | 条件成员访问 | name?.length   |
| ?.. | 条件级联   | obj?..method() |
| ??  | 空合并    | name ?? '默认'   |
| ??= | 空合并赋值  | name ??= '默认'  |
| !   | 非空断言   | name!          |

### 字符串

```dart
// 字符串插值：$ 插入变量，${} 插入表达式
String name = 'Dart';
int version = 3;
print('Hello, $name!');               // Hello, Dart!
print('版本：${version + 1}');        // 版本：4
print('大写：${name.toUpperCase()}'); // 大写：DART

// Python 对比：Python 用 f'Hello, {name}'
// JS 对比：JS 用 `Hello, ${name}`（反引号模板字符串）

// 多行字符串：三引号（与 Python 相同）
String multiLine = '''
第一行
第二行
第三行
''';

// 原始字符串：r 前缀，不处理转义（类似 Python 的 r''）
String path = r'C:\Users\dog\Documents';   // \ 不转义
String regex = r'\d+';

// 常用字符串方法
String str = '  Hello, Dart!  ';

print(str.trim());                    // 'Hello, Dart!'（去除首尾空白）
print(str.toUpperCase());             // '  HELLO, DART!  '
print(str.toLowerCase());             // '  hello, dart!  '
print(str.contains('Dart'));          // true
print(str.startsWith('  Hello'));     // true
print(str.replaceAll('Dart', 'World')); // '  Hello, World!  '
print(str.split(', '));               // ['  Hello', 'Dart!  ']
print(str.trim().length);             // 12
print('hello'.padLeft(10));           // '     hello'
print('hello'.padRight(10, '-'));     // 'hello-----'

// 字符串拼接
String a = 'Hello' + ' ' + 'World';  // 用 + 拼接
String b = 'Ha' * 3;                  // 'HaHaHa'（类似 Python）

```

### 集合类型

#### List（列表）

```dart
// 创建 List（类似 Python 的 list，JavaScript 的 Array）
List<int> numbers = [1, 2, 3, 4, 5];
var names = <String>['Alice', 'Bob', 'Charlie'];  // 类型参数写法
var mixed = [1, 'hello', true];     // 推断为 List<Object>

// 空 List
List<int> empty = [];
List<int> empty2 = List.empty(growable: true);

```

List 常用方法参数表：

| 方法                      | 参数                           | 返回类型        | 说明         |
| ----------------------- | ---------------------------- | ----------- | ---------- |
| add(value)              | value: E                     | void        | 末尾追加元素     |
| addAll(iterable)        | iterable: Iterable<E>        | void        | 追加多个元素     |
| insert(index, value)    | index: int, value: E         | void        | 在指定位置插入    |
| remove(value)           | value: Object?               | bool        | 删除第一个匹配元素  |
| removeAt(index)         | index: int                   | E           | 删除指定索引的元素  |
| indexOf(value)          | value: Object?               | int         | 返回第一次出现的索引 |
| contains(value)         | value: Object?               | bool        | 是否包含该元素    |
| sort(\[compare\])       | compare: int Function(E, E)? | void        | 排序（原地）     |
| sublist(start, \[end\]) | start: int, end: int?        | List<E>     | 切片         |
| join(\[separator\])     | separator: String            | String      | 拼接为字符串     |
| where(test)             | test: bool Function(E)       | Iterable<E> | 过滤         |
| map(convert)            | convert: T Function(E)       | Iterable<T> | 映射         |
| forEach(action)         | action: void Function(E)     | void        | 遍历         |

```dart
var fruits = ['apple', 'banana', 'cherry'];

// 增删改查
fruits.add('date');                  // ['apple', 'banana', 'cherry', 'date']
fruits.insert(1, 'avocado');         // ['apple', 'avocado', 'banana', ...]
fruits.remove('banana');             // 删除第一个 'banana'
fruits.removeAt(0);                  // 删除索引 0

// 访问
print(fruits[0]);                    // 第一个元素
print(fruits.last);                  // 最后一个元素
print(fruits.length);                // 长度

// 遍历（for...in 类似 Python 的 for...in）
for (var fruit in fruits) {
  print(fruit);
}

// 展开运算符（类似 JS 的 ...）
var list1 = [1, 2, 3];
var list2 = [0, ...list1, 4];        // [0, 1, 2, 3, 4]

// 集合 if 和集合 for（Dart 特有）
bool showExtra = true;
var items = [
  'item1',
  'item2',
  if (showExtra) 'item3',            // 条件包含
  for (var i in [4, 5]) 'item$i',   // 循环展开
];
// items: ['item1', 'item2', 'item3', 'item4', 'item5']

```

#### Map（字典）

```dart
// 创建 Map（类似 Python 的 dict，JavaScript 的 Object/Map）
Map<String, int> scores = {'Alice': 95, 'Bob': 87, 'Charlie': 92};
var config = <String, dynamic>{
  'host': 'localhost',
  'port': 8080,
  'debug': true,
};

```

Map 常用方法参数表：

| 方法/属性                      | 参数                             | 返回类型                    | 说明             |
| -------------------------- | ------------------------------ | ----------------------- | -------------- |
| map\[key\]                 | key: K                         | V?                      | 取值（不存在返回 null） |
| map\[key\] = value         | key: K, value: V               | —                       | 设置值            |
| containsKey(key)           | key: Object?                   | bool                    | 是否包含键          |
| containsValue(value)       | value: Object?                 | bool                    | 是否包含值          |
| remove(key)                | key: Object?                   | V?                      | 删除并返回对应值       |
| putIfAbsent(key, ifAbsent) | key: K, ifAbsent: V Function() | V                       | 键不存在时插入        |
| keys                       | —                              | Iterable<K>             | 所有键            |
| values                     | —                              | Iterable<V>             | 所有值            |
| entries                    | —                              | Iterable<MapEntry<K,V>> | 键值对            |
| forEach(action)            | action: void Function(K, V)    | void                    | 遍历             |

```dart
var scores = {'Alice': 95, 'Bob': 87};

// 访问
print(scores['Alice']);              // 95
print(scores['Unknown']);            // null（不存在返回 null，不抛异常）

// 安全访问
int? score = scores['Unknown'];
print(score ?? 0);                   // 0

// 遍历（Python 对比：for k, v in d.items()）
scores.forEach((key, value) {
  print('$key: $value');
});

// 用 entries 遍历
for (var entry in scores.entries) {
  print('${entry.key} 得了 ${entry.value} 分');
}

```

#### Set（集合）

```dart
// 创建 Set：无序，元素唯一（类似 Python 的 set）
Set<String> tags = {'dart', 'flutter', 'mobile'};
var nums = <int>{1, 2, 3, 2, 1};    // 实际：{1, 2, 3}

// 注意：{} 创建的是 Map，空 Set 必须用类型声明
var emptySet = <String>{};           // Set
var emptyMap = {};                   // Map<dynamic, dynamic>

// 常用操作
tags.add('android');
tags.remove('mobile');
print(tags.contains('dart'));        // true

// 集合运算
var a = {1, 2, 3, 4};
var b = {3, 4, 5, 6};
print(a.union(b));                   // {1, 2, 3, 4, 5, 6}
print(a.intersection(b));            // {3, 4}
print(a.difference(b));              // {1, 2}

```

### 运算符

```dart
// 算术运算符
print(10 ~/ 3);    // 3，整除（Python 的 //，JS 没有原生整除）
print(10 % 3);     // 1，取余
print(2.pow(3));   // 注意：Dart 没有 ** 运算符，用 pow() 函数

import 'dart:math';
print(pow(2, 10)); // 1024

// 级联运算符 ..（方法链，返回调用者本身）
// 类似 JavaScript 的链式调用，但更简洁
var list = []
  ..add(1)
  ..add(2)
  ..add(3);        // list 是 [1, 2, 3]

// 不用级联的写法：
var list2 = [];
list2.add(1);
list2.add(2);
list2.add(3);

// 类型测试运算符
var obj = 'hello';
print(obj is String);     // true（类似 Python 的 isinstance）
print(obj is! int);       // true（is not 的简写）

// 类型转换
num n = 3.7;
int i = n.toInt();        // 3（截断，不四舍五入）
double d = i.toDouble();  // 3.0
String s = i.toString();  // '3'
int parsed = int.parse('42');         // 42
double parsedD = double.parse('3.14'); // 3.14
int? tryParsed = int.tryParse('abc'); // null（不抛异常）

```

---

## 流程控制

### if/else

```dart
int score = 85;

// 基本 if/else（语法与 JS 相同）
if (score >= 90) {
  print('优秀');
} else if (score >= 75) {
  print('良好');
} else {
  print('需要努力');
}

// 三元表达式
String result = score >= 60 ? '及格' : '不及格';

// 注意：Dart 没有 JS 的隐式类型转换
// if (1) {}   // 编译错误，必须是 bool

```

### switch（含 Dart 3 模式匹配）

```dart
// 传统 switch（类似 Java/JavaScript）
String day = 'Monday';
switch (day) {
  case 'Monday':
  case 'Tuesday':
    print('工作日');
    break;
  case 'Saturday':
  case 'Sunday':
    print('周末');
    break;
  default:
    print('未知');
}

// Dart 3：switch 表达式（更简洁，类似函数式风格）
String dayType = switch (day) {
  'Saturday' || 'Sunday' => '周末',
  'Monday' || 'Tuesday' || 'Wednesday' || 'Thursday' || 'Friday' => '工作日',
  _ => '未知',                    // _ 是默认分支
};

// Dart 3：模式匹配（Pattern Matching）
Object value = 42;
switch (value) {
  case int n when n > 0:
    print('正整数：$n');
  case String s:
    print('字符串：$s');
  case null:
    print('空值');
  default:
    print('其他');
}

```

### 循环

```dart
// for 循环（经典 C 风格）
for (int i = 0; i < 5; i++) {
  print(i);   // 0 1 2 3 4
}

// for...in：遍历可迭代对象（类似 Python 的 for...in）
var fruits = ['apple', 'banana', 'cherry'];
for (var fruit in fruits) {
  print(fruit);
}

// while 循环
int count = 0;
while (count < 3) {
  print(count);
  count++;
}

// do...while：至少执行一次
int n = 0;
do {
  print(n);
  n++;
} while (n < 3);

// break 和 continue
for (int i = 0; i < 10; i++) {
  if (i == 3) continue;   // 跳过 3
  if (i == 7) break;      // 遇到 7 停止
  print(i);               // 0 1 2 4 5 6
}

// 带标签的 break（跳出多层循环，Python 没有此特性）
outer:
for (int i = 0; i < 3; i++) {
  for (int j = 0; j < 3; j++) {
    if (i == 1 && j == 1) break outer;  // 直接跳出外层循环
    print('$i,$j');
  }
}

```

---

## 函数

### 基本函数声明

```dart
// 返回类型 函数名(参数列表) { 函数体 }
int add(int a, int b) {
  return a + b;
}

// void：无返回值（类似 Python 不写 return 或 return None）
void greet(String name) {
  print('Hello, $name!');
}

// 返回类型可推断（但建议显式声明）
String getVersion() => 'Dart 3.0';   // 箭头函数

// 调用
print(add(3, 4));   // 7
greet('Alice');      // Hello, Alice!

```

### 可选参数

```dart
// 位置可选参数：用 [] 包裹，类型必须可空或有默认值
String greet(String name, [String? title, int count = 1]) {
  String prefix = title != null ? '$title ' : '';
  return '$prefix$name' * count;
}

print(greet('Alice'));               // Alice
print(greet('Bob', 'Mr.'));          // Mr. Bob
print(greet('Hi', null, 3));         // HiHiHi

// 命名参数：用 {} 包裹，调用时指定参数名（推荐，Flutter 中大量使用）
void createUser({
  required String name,              // required：调用时必须传
  int age = 0,                       // 有默认值，可选
  String? email,                     // 可空，可选
}) {
  print('$name, $age, $email');
}

// 调用命名参数函数
createUser(name: 'Alice');                           // Alice, 0, null
createUser(name: 'Bob', age: 25, email: 'b@x.com'); // Bob, 25, b@x.com
createUser(age: 30, name: 'Charlie');                // 命名参数顺序可任意

// Python 对比：Python 用 def f(a, b=0, **kwargs)
// JS 对比：JS 用解构参数 function f({ name, age = 0 } = {})

```

命名参数规则总结：

| 参数写法                   | 是否必须传 | 说明           |
| ---------------------- | ----- | ------------ |
| {required String name} | 是     | 调用时必须提供      |
| {String? name}         | 否     | 可不传，默认为 null |
| {String name = '默认'}   | 否     | 可不传，有默认值     |
| \[String? name\]       | 否     | 位置可选，按顺序传    |

### 箭头函数与匿名函数

```dart
// 箭头函数：单表达式函数的简写
int square(int x) => x * x;
bool isEven(int n) => n % 2 == 0;

// 匿名函数（Lambda）：没有名字的函数
var multiply = (int a, int b) => a * b;
print(multiply(3, 4));    // 12

// 完整写法的匿名函数
var greet = (String name) {
  return 'Hello, $name!';
};

// 作为参数传递（高阶函数）
var numbers = [1, 2, 3, 4, 5];
numbers.forEach((n) => print(n));   // 打印每个数字

```

### 高阶函数

```dart
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// map：映射，返回新的 Iterable（类似 Python 的 map()，JS 的 Array.map()）
var squares = numbers.map((n) => n * n).toList();
print(squares);   // [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

// where：过滤（类似 Python 的 filter()，JS 的 Array.filter()）
var evens = numbers.where((n) => n % 2 == 0).toList();
print(evens);     // [2, 4, 6, 8, 10]

// fold：折叠/归约（类似 Python 的 reduce()，JS 的 Array.reduce()）
int sum = numbers.fold(0, (acc, n) => acc + n);
print(sum);       // 55

// reduce：类似 fold，但无初始值
int product = numbers.reduce((a, b) => a * b);
print(product);   // 3628800

// any：是否存在满足条件的元素（类似 Python 的 any()）
bool hasEven = numbers.any((n) => n % 2 == 0);
print(hasEven);   // true

// every：是否全部满足条件（类似 Python 的 all()）
bool allPositive = numbers.every((n) => n > 0);
print(allPositive);  // true

// take / skip：取前 N 个 / 跳过前 N 个
var first3 = numbers.take(3).toList();   // [1, 2, 3]
var skip3 = numbers.skip(3).toList();    // [4, 5, 6, 7, 8, 9, 10]

// 链式调用
var result = numbers
    .where((n) => n % 2 == 0)           // 保留偶数
    .map((n) => n * n)                  // 求平方
    .where((n) => n > 20)               // 大于 20 的
    .toList();
print(result);    // [36, 64, 100]

```

---

## 面向对象

### 基本类

```dart
class Person {
  // 属性（实例变量）
  String name;
  int age;
  String? email;   // 可空属性

  // 普通构造函数
  Person(this.name, this.age);   // this.name 语法自动赋值
  // 等价于：
  // Person(String name, int age) {
  //   this.name = name;
  //   this.age = age;
  // }

  // 方法
  void introduce() {
    print('我是 $name，今年 $age 岁');
  }

  // 重写 toString（类似 Python 的 __str__）
  @override
  String toString() => 'Person($name, $age)';
}

void main() {
  var p = Person('Alice', 25);   // 不需要 new 关键字（Dart 2+）
  p.introduce();                 // 我是 Alice，今年 25 岁
  print(p);                      // Person(Alice, 25)
}

```

### 命名构造函数与工厂构造函数

```dart
class Point {
  double x;
  double y;

  // 普通构造函数
  Point(this.x, this.y);

  // 命名构造函数：创建特殊实例（Python 对比：classmethod）
  Point.origin() : x = 0, y = 0;            // 初始化列表
  Point.fromJson(Map<String, double> json)
      : x = json['x']!,
        y = json['y']!;

  // 工厂构造函数：可以返回缓存对象或子类实例
  static final Map<String, Point> _cache = {};
  factory Point.cached(double x, double y) {
    final key = '$x,$y';
    return _cache.putIfAbsent(key, () => Point(x, y));
  }

  double distanceTo(Point other) {
    import 'dart:math';
    return sqrt(pow(x - other.x, 2) + pow(y - other.y, 2));
  }

  @override
  String toString() => 'Point($x, $y)';
}

void main() {
  var origin = Point.origin();          // (0, 0)
  var p1 = Point.fromJson({'x': 3.0, 'y': 4.0});   // (3, 4)
  var p2 = Point.cached(1.0, 2.0);     // 从缓存获取或新建
}

```

### getter 与 setter

```dart
class Circle {
  double _radius;   // _ 前缀表示私有（仅在同一文件/库内私有）

  Circle(this._radius);

  // getter：像属性一样访问
  double get radius => _radius;
  double get area => 3.14159 * _radius * _radius;
  double get circumference => 2 * 3.14159 * _radius;

  // setter：像属性一样赋值
  set radius(double value) {
    if (value < 0) throw ArgumentError('半径不能为负');
    _radius = value;
  }
}

void main() {
  var c = Circle(5.0);
  print(c.radius);          // 5.0（调用 getter）
  print(c.area);            // 78.53975
  c.radius = 10.0;          // 调用 setter
  // c.radius = -1;         // 抛出 ArgumentError
}

```

### 继承与多态

```dart
// 基类
class Animal {
  String name;

  Animal(this.name);

  // 可被子类重写的方法
  void speak() {
    print('$name 发出声音');
  }

  String get description => '动物：$name';
}

// 子类（extends 类似 Python 的类继承，JS 的 extends）
class Dog extends Animal {
  String breed;

  // super 调用父类构造函数（类似 Python 的 super().__init__()）
  Dog(String name, this.breed) : super(name);

  // @override 重写父类方法（Python 不需要此注解）
  @override
  void speak() {
    print('$name 汪汪叫！');
  }

  @override
  String get description => '${super.description}，品种：$breed';

  void fetch() {
    print('$name 捡球！');
  }
}

class Cat extends Animal {
  Cat(String name) : super(name);

  @override
  void speak() {
    print('$name 喵喵叫～');
  }
}

void main() {
  List<Animal> animals = [Dog('旺财', '哈士奇'), Cat('咪咪'), Dog('来福', '金毛')];

  for (var animal in animals) {
    animal.speak();    // 多态：根据实际类型调用对应方法
  }

  // 类型检查与转换
  var first = animals[0];
  if (first is Dog) {
    first.fetch();     // 自动类型收窄（Smart Cast），不需要强制转换
  }

  // 强制转换
  var dog = animals[0] as Dog;
  dog.fetch();
}

```

### 抽象类、接口与混入

```dart
// 抽象类：不能直接实例化（类似 Python 的 ABC）
abstract class Shape {
  double get area;           // 抽象 getter，子类必须实现
  double get perimeter;

  void describe() {          // 普通方法，子类可直接继承
    print('面积：$area，周长：$perimeter');
  }
}

// Dart 中没有专门的 interface 关键字
// 每个类都隐式定义了接口，用 implements 实现（必须实现所有方法）
abstract class Drawable {
  void draw();
}

abstract class Resizable {
  void resize(double factor);
}

// implements：实现多个接口（类似 Java 的 implements）
// 注意：implements 必须实现接口的所有成员，包括普通方法
class Rectangle extends Shape implements Drawable, Resizable {
  double width;
  double height;

  Rectangle(this.width, this.height);

  @override
  double get area => width * height;

  @override
  double get perimeter => 2 * (width + height);

  @override
  void draw() {
    print('绘制矩形 ${width}x$height');
  }

  @override
  void resize(double factor) {
    width *= factor;
    height *= factor;
  }
}

// mixin：混入，向类添加功能（类似 Python 的 Mixin 模式）
// mixin 不能有构造函数
mixin Logger {
  void log(String message) {
    print('[LOG] $message');
  }
}

mixin Serializable {
  Map<String, dynamic> toJson();   // 抽象方法，要求使用方实现
  String serialize() => toJson().toString();
}

// with 使用混入
class User with Logger, Serializable {
  String name;
  int age;

  User(this.name, this.age);

  @override
  Map<String, dynamic> toJson() => {'name': name, 'age': age};

  void save() {
    log('保存用户：$name');     // 来自 Logger
    print(serialize());          // 来自 Serializable
  }
}

```

### 枚举

```dart
// 普通枚举
enum Direction { north, south, east, west }

void main() {
  var dir = Direction.north;
  print(dir);           // Direction.north
  print(dir.name);      // north（Dart 2.15+）
  print(dir.index);     // 0

  switch (dir) {
    case Direction.north:
      print('向北');
    default:
      print('其他方向');
  }
}

// 增强枚举（Dart 2.17+）：枚举值可以有属性和方法
enum Planet {
  mercury(3.303e+23, 2.4397e6),
  venus(4.869e+24, 6.0518e6),
  earth(5.976e+24, 6.37814e6);

  // 属性
  final double mass;
  final double radius;

  // 常量构造函数
  const Planet(this.mass, this.radius);

  // 方法
  double get surfaceGravity {
    const g = 6.67430e-11;
    return g * mass / (radius * radius);
  }
}

void main() {
  print(Planet.earth.surfaceGravity);    // 约 9.8
  for (var p in Planet.values) {
    print('${p.name}: ${p.surfaceGravity.toStringAsFixed(2)}');
  }
}

```

### 泛型

```dart
// 泛型类（类似 Python 的 Generic[T]，Java/TS 的泛型）
class Box<T> {
  T value;

  Box(this.value);

  T getValue() => value;

  @override
  String toString() => 'Box<$T>($value)';
}

void main() {
  var intBox = Box<int>(42);
  var strBox = Box<String>('hello');
  print(intBox);    // Box<int>(42)
  print(strBox);    // Box<String>(hello)
}

// 泛型函数
T first<T>(List<T> list) {
  if (list.isEmpty) throw StateError('列表为空');
  return list.first;
}

print(first([1, 2, 3]));          // 1
print(first(['a', 'b', 'c']));    // a

// 泛型约束
class NumberBox<T extends num> {   // T 必须是 num 或其子类
  T value;
  NumberBox(this.value);
  T doubled() => (value * 2) as T;
}

```

---

## 异步编程

### Future

Future 代表一个异步操作的最终结果，类似 JavaScript 的 Promise。

```dart
import 'dart:async';

// 创建 Future
Future<String> fetchData() {
  return Future.delayed(
    Duration(seconds: 2),
    () => '从服务器获取的数据',
  );
}

// Future.value：立即完成的 Future
Future<int> getNumber() => Future.value(42);

// Future.error：立即失败的 Future
Future<int> getError() => Future.error('出错了！');

// then/catchError/whenComplete 链式调用（类似 JS 的 .then().catch().finally()）
void fetchWithChain() {
  fetchData()
      .then((data) {
        print('获取成功：$data');
        return data.toUpperCase();   // 可以继续 then
      })
      .then((upperData) {
        print('处理后：$upperData');
      })
      .catchError((error) {
        print('错误：$error');
      })
      .whenComplete(() {
        print('无论成功失败都执行（类似 finally）');
      });
}

// Future.wait：等待多个 Future 同时完成（类似 JS 的 Promise.all()）
Future<void> fetchMultiple() async {
  var results = await Future.wait([
    Future.delayed(Duration(seconds: 1), () => '结果1'),
    Future.delayed(Duration(seconds: 2), () => '结果2'),
    Future.delayed(Duration(seconds: 1), () => '结果3'),
  ]);
  print(results);   // ['结果1', '结果2', '结果3']，约 2 秒后输出
}

// Future.any：任意一个完成就返回（类似 JS 的 Promise.race()）
Future<void> raceExample() async {
  var first = await Future.any([
    Future.delayed(Duration(seconds: 3), () => '慢的'),
    Future.delayed(Duration(seconds: 1), () => '快的'),
  ]);
  print(first);   // '快的'
}

```

### async/await

```dart
// async/await：让异步代码写起来像同步代码（与 JS/Python 的 async/await 几乎相同）
Future<String> getUserName(int id) async {
  // 模拟网络请求
  await Future.delayed(Duration(seconds: 1));
  return 'User_$id';
}

Future<void> main() async {
  print('开始');

  // await：等待 Future 完成，函数必须标记为 async
  String name = await getUserName(1);
  print('用户名：$name');

  print('结束');
}

// 异步错误处理（try/catch 与同步代码相同）
Future<void> safeOperation() async {
  try {
    var result = await Future.error('网络超时');
    print(result);
  } catch (e) {
    print('捕获错误：$e');
  } finally {
    print('清理资源');
  }
}

// 并发：同时启动多个异步操作（不等待）
Future<void> concurrentExample() async {
  // 错误写法：顺序等待，总耗时 = 各任务之和
  var r1 = await Future.delayed(Duration(seconds: 2), () => '任务1');
  var r2 = await Future.delayed(Duration(seconds: 2), () => '任务2');
  // 总耗时约 4 秒

  // 正确写法：并发启动，总耗时 = 最长任务
  var f1 = Future.delayed(Duration(seconds: 2), () => '任务1');
  var f2 = Future.delayed(Duration(seconds: 2), () => '任务2');
  var results = await Future.wait([f1, f2]);
  // 总耗时约 2 秒
}

```

### Stream

Stream 是一系列异步事件，类似 Node.js 的 Stream 或 RxJS 的 Observable。

```dart
import 'dart:async';

// 创建简单 Stream
Stream<int> countStream(int max) async* {
  for (int i = 0; i < max; i++) {
    await Future.delayed(Duration(milliseconds: 500));
    yield i;   // yield 产生一个值（类似 Python 的 generator）
  }
}

// 监听 Stream
void listenToStream() {
  var stream = countStream(5);

  stream.listen(
    (data) => print('收到：$data'),
    onError: (error) => print('错误：$error'),
    onDone: () => print('Stream 完成'),
  );
}

// StreamController：手动控制 Stream
void streamControllerExample() {
  var controller = StreamController<String>();

  // 订阅
  controller.stream.listen((data) {
    print('收到消息：$data');
  });

  // 发送数据
  controller.add('消息1');
  controller.add('消息2');
  controller.add('消息3');
  controller.close();   // 关闭 Stream
}

// await for：在 async 函数中遍历 Stream
Future<void> processStream() async {
  await for (var value in countStream(5)) {
    print('处理：$value');
  }
  print('所有数据处理完毕');
}

// Stream 转换操作
void streamTransform() {
  Stream.fromIterable([1, 2, 3, 4, 5])
      .where((n) => n % 2 == 0)      // 过滤偶数
      .map((n) => n * n)             // 求平方
      .listen(print);                // 输出：4 16
}

// 广播 Stream：可以被多个监听器订阅
void broadcastStreamExample() {
  var controller = StreamController<int>.broadcast();

  controller.stream.listen((d) => print('监听器1：$d'));
  controller.stream.listen((d) => print('监听器2：$d'));

  controller.add(1);   // 两个监听器都会收到
  controller.close();
}

```

Flutter 中会大量使用 StreamBuilder 组件来根据 Stream 数据更新 UI，详见 [Flutter入门](https://blog.vercanti.com/flutter-ru-men/)。

---

## 库与包

### import 语句

```dart
// 导入 Dart 内置库（dart: 前缀）
import 'dart:math';           // 数学函数
import 'dart:async';          // 异步支持
import 'dart:io';             // 文件、网络 IO
import 'dart:convert';        // JSON、UTF-8 编解码

// 导入 pub.dev 包（在 pubspec.yaml 中声明依赖后才能用）
import 'package:http/http.dart';
import 'package:path/path.dart';

// 导入本地文件
import 'utils/helper.dart';
import '../models/user.dart';

// as：给库起别名，避免命名冲突
import 'dart:math' as math;
print(math.pi);               // 使用 math.pi 而不是直接 pi

// show：只导入指定成员
import 'dart:math' show pi, sqrt, pow;

// hide：导入除指定成员外的所有内容
import 'dart:math' hide Random;

// 导出：让本文件的内容对外可见
export 'src/model.dart';
export 'src/utils.dart' show helper;

```

### pubspec.yaml

```yaml
# pubspec.yaml：Dart/Flutter 项目的配置文件（类似 Python 的 pyproject.toml 或 JS 的 package.json）
name: my_app
description: 我的 Dart 应用
version: 1.0.0

environment:
  sdk: '>=3.0.0 <4.0.0'   # Dart SDK 版本约束

dependencies:
  # pub.dev 包
  http: ^1.1.0             # ^ 表示兼容性版本（>=1.1.0 <2.0.0）
  path: ^1.8.3
  json_annotation: ^4.8.0

dev_dependencies:          # 只在开发时使用的包
  test: ^1.24.0
  lints: ^2.1.0
  build_runner: ^2.4.6

# Flutter 特有配置
flutter:
  assets:
    - assets/images/
  fonts:
    - family: MyFont
      fonts:
        - asset: fonts/MyFont-Regular.ttf

```

常用 pub 命令：

| 命令                   | 说明                   |
| -------------------- | -------------------- |
| dart pub get         | 安装 pubspec.yaml 中的依赖 |
| dart pub add http    | 添加依赖并安装              |
| dart pub remove http | 移除依赖                 |
| dart pub upgrade     | 升级所有依赖               |
| dart pub outdated    | 查看过期的依赖              |

---

## Dart 3 新特性

### 模式匹配（Pattern Matching）

```dart
// switch 表达式（返回值）
int statusCode = 404;
String message = switch (statusCode) {
  200 => '成功',
  301 || 302 => '重定向',
  400 => '请求错误',
  404 => '未找到',
  500 => '服务器错误',
  _ => '未知状态码',
};

// 解构模式
var point = (x: 3, y: 4);   // 记录类型
var (x: px, y: py) = point;  // 解构
print('$px, $py');           // 3, 4

// 列表模式解构
var [first, second, ...rest] = [1, 2, 3, 4, 5];
print(first);   // 1
print(rest);    // [3, 4, 5]

// 类型模式
Object? value = 'hello';
if (value case String s when s.length > 3) {
  print('长字符串：$s');
}

```

### 记录类型（Records）

```dart
// Records：轻量级的不可变数据结构（类似 Python 的 namedtuple）
// 可以从函数返回多个值，不需要定义类

// 位置记录
(String, int) getNameAndAge() {
  return ('Alice', 25);
}

// 命名记录
({String name, int age}) getUser() {
  return (name: 'Bob', age: 30);
}

void main() {
  var (name, age) = getNameAndAge();   // 解构
  print('$name, $age');

  var user = getUser();
  print('${user.name}, ${user.age}');  // 命名字段访问
}

```

### 密封类（sealed class）

```dart
// sealed class：限制继承层次，配合模式匹配使用
// 所有子类必须在同一文件中定义
sealed class Shape {}

class Circle extends Shape {
  double radius;
  Circle(this.radius);
}

class Rectangle extends Shape {
  double width, height;
  Rectangle(this.width, this.height);
}

class Triangle extends Shape {
  double base, height;
  Triangle(this.base, this.height);
}

// 编译器知道 Shape 的所有子类，switch 可以穷举检查
double calculateArea(Shape shape) => switch (shape) {
  Circle c => 3.14159 * c.radius * c.radius,
  Rectangle r => r.width * r.height,
  Triangle t => 0.5 * t.base * t.height,
  // 无需 default：编译器确认已覆盖所有情况
};

```

---

## 综合实战：命令行 Todo 应用

下面是一个完整可运行的命令行 Todo 应用，演示类、集合、异步、文件读写。

```dart
// todo_app.dart
import 'dart:io';
import 'dart:convert';

// Todo 数据模型
class Todo {
  final int id;
  String title;
  bool isDone;
  final DateTime createdAt;

  // 命名构造函数：从 JSON 反序列化
  Todo({
    required this.id,
    required this.title,
    this.isDone = false,
    DateTime? createdAt,
  }) : createdAt = createdAt ?? DateTime.now();

  // 工厂构造函数：从 Map 创建
  factory Todo.fromJson(Map<String, dynamic> json) {
    return Todo(
      id: json['id'] as int,
      title: json['title'] as String,
      isDone: json['isDone'] as bool,
      createdAt: DateTime.parse(json['createdAt'] as String),
    );
  }

  // 序列化为 Map
  Map<String, dynamic> toJson() => {
        'id': id,
        'title': title,
        'isDone': isDone,
        'createdAt': createdAt.toIso8601String(),
      };

  @override
  String toString() {
    final status = isDone ? '[完成]' : '[待办]';
    return '$status #$id $title';
  }
}

// Todo 管理器
class TodoManager {
  final List<Todo> _todos = [];
  final String _filePath;
  int _nextId = 1;

  TodoManager(this._filePath);

  // 从文件加载（异步）
  Future<void> load() async {
    final file = File(_filePath);
    if (!await file.exists()) return;

    try {
      final content = await file.readAsString();
      final List<dynamic> jsonList = jsonDecode(content) as List;
      _todos.clear();
      for (var item in jsonList) {
        final todo = Todo.fromJson(item as Map<String, dynamic>);
        _todos.add(todo);
        if (todo.id >= _nextId) {
          _nextId = todo.id + 1;
        }
      }
      print('加载了 ${_todos.length} 条 Todo');
    } catch (e) {
      print('加载失败：$e');
    }
  }

  // 保存到文件（异步）
  Future<void> save() async {
    final file = File(_filePath);
    final jsonList = _todos.map((t) => t.toJson()).toList();
    await file.writeAsString(jsonEncode(jsonList));
  }

  // 添加 Todo
  Todo add(String title) {
    final todo = Todo(id: _nextId++, title: title);
    _todos.add(todo);
    return todo;
  }

  // 完成 Todo
  bool complete(int id) {
    final todo = _todos.where((t) => t.id == id).firstOrNull;
    if (todo == null) return false;
    todo.isDone = true;
    return true;
  }

  // 删除 Todo
  bool delete(int id) {
    final before = _todos.length;
    _todos.removeWhere((t) => t.id == id);
    return _todos.length < before;
  }

  // 获取所有 Todo
  List<Todo> getAll() => List.unmodifiable(_todos);

  // 获取待办
  List<Todo> getPending() => _todos.where((t) => !t.isDone).toList();

  // 获取已完成
  List<Todo> getCompleted() => _todos.where((t) => t.isDone).toList();

  // 统计信息
  Map<String, int> getStats() => {
        'total': _todos.length,
        'pending': getPending().length,
        'completed': getCompleted().length,
      };
}

// 打印帮助信息
void printHelp() {
  print('''
命令列表：
  add <标题>     添加 Todo
  list           查看所有 Todo
  done <id>      标记为完成
  delete <id>    删除 Todo
  stats          统计信息
  help           显示帮助
  exit           退出
''');
}

// 主函数（异步）
Future<void> main() async {
  final manager = TodoManager('todos.json');

  // 启动时加载数据
  await manager.load();

  print('=== Dart Todo 应用 ===');
  print('输入 help 查看命令');

  // 主循环
  while (true) {
    stdout.write('> ');
    final input = stdin.readLineSync()?.trim();

    if (input == null || input.isEmpty) continue;

    // 解析命令和参数
    final parts = input.split(' ');
    final command = parts[0].toLowerCase();
    final args = parts.skip(1).join(' ');

    switch (command) {
      case 'add':
        if (args.isEmpty) {
          print('用法：add <标题>');
          break;
        }
        final todo = manager.add(args);
        await manager.save();
        print('已添加：$todo');

      case 'list':
        final todos = manager.getAll();
        if (todos.isEmpty) {
          print('暂无 Todo');
        } else {
          for (var todo in todos) {
            print(todo);
          }
        }

      case 'done':
        final id = int.tryParse(args);
        if (id == null) {
          print('用法：done <id>');
          break;
        }
        if (manager.complete(id)) {
          await manager.save();
          print('已完成 #$id');
        } else {
          print('未找到 #$id');
        }

      case 'delete':
        final id = int.tryParse(args);
        if (id == null) {
          print('用法：delete <id>');
          break;
        }
        if (manager.delete(id)) {
          await manager.save();
          print('已删除 #$id');
        } else {
          print('未找到 #$id');
        }

      case 'stats':
        final stats = manager.getStats();
        print('总计：${stats['total']}，待办：${stats['pending']}，完成：${stats['completed']}');

      case 'help':
        printHelp();

      case 'exit':
        print('再见！');
        exit(0);

      default:
        print('未知命令：$command。输入 help 查看命令列表');
    }
  }
}

```

运行方法：

```bash
# 安装 Dart SDK 后直接运行
dart run todo_app.dart

# 编译为可执行文件
dart compile exe todo_app.dart -o todo_app
./todo_app

```

---

## 与 Python/JavaScript 速查对比

| 概念    | Python                            | JavaScript                    | Dart                      |
| ----- | --------------------------------- | ----------------------------- | ------------------------- |
| 变量声明  | x = 1                             | let x = 1                     | var x = 1                 |
| 常量    | （无原生支持）                           | const x = 1                   | final x = 1 / const x = 1 |
| 类型标注  | x: int = 1                        | TypeScript: let x: number = 1 | int x = 1                 |
| 空值    | None                              | null / undefined              | null                      |
| 字符串插值 | f'{name}'                         | \`${name}\`                   | '$name'                   |
| 列表    | list                              | Array                         | List                      |
| 字典    | dict                              | Object / Map                  | Map                       |
| 集合    | set                               | Set                           | Set                       |
| 异步函数  | async def f()                     | async function f()            | Future<T> f() async       |
| 等待异步  | await f()                         | await f()                     | await f()                 |
| 继承    | class A(B)                        | class A extends B             | class A extends B         |
| 接口    | ABC / Protocol                    | （TypeScript interface）        | class A implements B      |
| 混入    | Mixin 模式                          | （无原生支持）                       | mixin M / with M          |
| 类型检查  | isinstance(x, T)                  | x instanceof T                | x is T                    |
| 整除    | //                                | Math.floor(a/b)               | \~/                       |
| 打印    | print()                           | console.log()                 | print()                   |
| 主函数   | if \_\_name\_\_ == '\_\_main\_\_' | （无，直接运行）                      | void main()               |

---

## 踩坑与注意事项

**1\. 空安全陷阱**

```dart
// 错误：可空类型直接调用方法
String? name = null;
// print(name.length);   // 运行时错误

// 正确：先检查
if (name != null) {
  print(name.length);    // 类型收窄，这里 name 是 String
}
// 或
print(name?.length);     // 返回 null
print(name?.length ?? 0); // 返回 0

```

**2\. const 与 final 的区别**

```dart
// final：运行时常量，可以是运行时才知道的值
final now = DateTime.now();   // 合法

// const：编译期常量，必须是编译时已知的值
// const now2 = DateTime.now(); // 编译错误：DateTime.now() 是运行时值

```

**3\. List 的类型安全**

```dart
// Dart 的泛型是具体化的（Reified），运行时保留类型信息
List<String> strings = ['a', 'b', 'c'];
// strings.add(1);   // 编译错误，不像 Python 列表可以混放任意类型

```

**4\. == 比较的是值，不是引用**

```dart
// Dart 默认 == 比较值（对于基本类型）
String a = 'hello';
String b = 'hello';
print(a == b);          // true（不像 Java 需要 .equals()）

// 比较引用用 identical()
print(identical(a, b)); // 可能是 true（字符串驻留）或 false

```

**5\. 异步函数返回类型**

```dart
// async 函数自动包装返回值为 Future
Future<int> getNumber() async {
  return 42;   // 实际返回 Future<int>，不需要 Future.value(42)
}

// void async 函数的错误不会被捕获，应改为 Future<void>
Future<void> riskyOperation() async {
  throw Exception('出错了');
}
// 调用时必须 await 或 .catchError()

```

**6\. for...in 不能获取索引**

```dart
var list = ['a', 'b', 'c'];
// 需要索引时，用 asMap() 或 enumerate
list.asMap().forEach((index, value) {
  print('$index: $value');
});

// 或者用普通 for 循环
for (int i = 0; i < list.length; i++) {
  print('$i: ${list[i]}');
}

```

---

---

## 最佳实践

**优先用 `final` 和 `const`**：Dart 中 `const` 在编译期确定，`final` 在运行时赋值一次。能用 `const` 就用 `const`，减少运行时开销，IDE 会自动提示。

**空安全（Null Safety）中用 `?.` 和 `??` 替代手动判空**：

```dart
// 好
final name = user?.profile?.name ?? 'Guest';

// 差：冗长且容易遗漏
String name = 'Guest';
if (user != null && user.profile != null) {
  name = user.profile!.name;
}

```

**异步优先用 `async/await`，避免 `.then` 链**：`async/await` 使控制流更线性，错误处理用 `try/catch` 而非 `.catchError`，可读性更高。

**用命名构造函数区分不同初始化场景**：Dart 支持多个命名构造函数，比重载参数更清晰：

```dart
class User {
  User.fromJson(Map<String, dynamic> json) : name = json['name'];
  User.anonymous() : name = 'Guest';
}

```

**扩展方法（Extension）给现有类型添加功能**：不需要继承或包装，直接为 `String`、`List` 等添加业务方法，保持调用链风格：

```dart
extension StringUtils on String {
  bool get isValidEmail => contains('@') && contains('.');
}

'user@example.com'.isValidEmail; // true

```

---

## 常见陷阱

### 陷阱：`!` 运算符在 null 值上抛出 `Null check operator used on a null value`

**现象：** 运行时崩溃，堆栈指向某个使用 `!` 的位置。  
**原因：** 用 `!` 强制解包了实际为 `null` 的可空变量，编译器不报错但运行时抛出。  
**解决：** 用 `?.` 安全访问，或用 `??` 提供默认值；只在能确保不为 null 时使用 `!`，并加注释说明理由。

### 陷阱：`List` 的 `forEach` 中无法 `break`

**现象：** 尝试在 `forEach` 回调中 `return` 期望退出循环，但循环仍然继续。  
**原因：** `forEach` 接受回调函数，`return` 只退出回调，不退出外层循环。  
**解决：** 改用 `for...in` 循环，可以正常使用 `break`/`continue`：

```dart
// 差：return 无法跳出 forEach
list.forEach((item) {
  if (item.id == targetId) return; // 只跳过当前回调，不退出
});

// 好：for...in 支持 break
for (final item in list) {
  if (item.id == targetId) break;
}

```

### 陷阱：`async` 函数中 `Future` 未 `await` 导致异常被吞

**现象：** 调用异步函数后程序行为异常，但没有看到任何报错。  
**原因：** 未 `await` 的 `Future` 中抛出的异常不会传播到调用方，会被静默忽略（除非设置了全局 `runZonedGuarded`）。  
**解决：** 所有 `Future` 调用都加 `await`，或用 `unawaited(future)` 明确表示有意不等待，并自行处理错误。

---

## 参见

[Flutter入门](https://blog.vercanti.com/flutter-ru-men/)  
[Flutter状态管理](https://blog.vercanti.com/flutter-zhuang-tai-guan-li/)