1.Dart语言基础

2026-06-02 14:18 121 阅读

一.Dart语言基础

面向Java开发者的Dart学习笔记,通过对比让你快速掌握Dart特性

1. 变量声明

Dart中的变量声明方式

// 方式1:显式类型声明(类似Java)
String name = "张三";
int age = 25;
double height = 1.75;

// 方式2:使用var(类型推断)
var city = "北京";    // 编译器推断为String
var score = 95.5;    // 推断为double

// 方式3:使用dynamic(动态类型)
dynamic anything = "hello";
anything = 123;      // 可以改变类型
anything = true;     // 又可以变成布尔值

与Java的关键区别

特性 Dart Java
类型推断 支持 var Java 10+ 支持 var
动态类型 支持 dynamic 不支持
所有类型 都是对象 有基本类型

重要提示:Dart中没有基本类型intdoublebool 都是类,这也是为什么可以调用 5.toString()


2. 常量声明 - const

const 表示编译时常量,值在编译时就必须确定。

// 正确用法
const PI = 3.14159;
const appName = "我的应用";
const List<int> emptyList = [];  // 空列表常量

// 错误用法 - 编译错误
const currentTime = DateTime.now();  // ❌ 运行时才能确定的值

// const 创建不可变集合
const numbers = [1, 2, 3];
// numbers.add(4);  // ❌ 不可变集合不能修改

与Java对比

Java中 finalstatic final 的组合才能达到类似效果:

// Java
public static final double PI = 3.14159;

3. 常量声明 - final

final 表示运行时常量,只能赋值一次。

// 正确用法
final currentTime = DateTime.now();  // ✅ 运行时确定没问题
final name = "李四";
final list = [1, 2, 3];

// final 变量可以修改引用对象的内部状态
final list = [1, 2, 3];
list.add(4);  // ✅ 可以修改,因为是同一个列表对象
// list = [4, 5, 6];  // ❌ 不能重新赋值

// final 和 const 的区别
const constList = [1, 2, 3];
final finalList = [1, 2, 3];

constList.add(4);  // ❌ 错误:const创建的是不可变集合
finalList.add(4);  // ✅ 正确:finalList引用的集合是可变的

4. 字符串类型 - String

Dart的字符串功能非常强大,支持多种写法。

字符串定义

// 单引号(最常用)
String name = '张三';

// 双引号
String name2 = "李四";

// 三引号(多行字符串)
String multiLine = '''
这是第一行
这是第二行
这是第三行
''';

// 原始字符串(不转义)
String rawString = r'换行符是:\n,不会真的换行';

字符串插值(核心特性)

String name = "王五";
int age = 30;

// 基本插值:$变量名
print("姓名:$name");        // 输出:姓名:王五

// 复杂插值:${表达式}
print("明年年龄:${age + 1}");  // 输出:明年年龄:31
print("姓名大写:${name.toUpperCase()}");  // 输出:姓名大写:王五

// 对象属性插值
class Person {
  String name;
  Person(this.name);
}

var p = Person("赵六");
print("对象姓名:${p.name}");  // 输出:对象姓名:赵六

字符串操作

String str = "Hello Dart";

// 常用方法
print(str.length);           // 10
print(str.toUpperCase());    // HELLO DART
print(str.toLowerCase());    // hello dart
print(str.contains("Dart")); // true
print(str.startsWith("He")); // true
print(str.endsWith("rt"));   // true
print(str.substring(0, 5));  // Hello

// 字符串拼接
String s1 = "Hello";
String s2 = "World";

// 方式1:+ 运算符
String s3 = s1 + " " + s2;   // Hello World

// 方式2:相邻字符串自动拼接
String s4 = "Hello" " " "World";  // Hello World

// 方式3:插值(推荐)
String s5 = "$s1 $s2";  // Hello World

5. 数字类型

Dart有两种数字类型:intdouble,都是64位。

基本使用

// 整数
int age = 25;
int hex = 0xDEADBEEF;  // 十六进制

// 浮点数
double height = 1.75;
double pi = 3.1415926;
double scientific = 1.42e5;  // 科学计数法:142000

// 类型转换
int a = 10;
double b = a.toDouble();     // 10.0

double c = 3.14;
int d = c.toInt();           // 3(直接截断,不是四舍五入)

// 字符串转数字
String numStr = "123";
int e = int.parse(numStr);   // 123
double f = double.parse("3.14");  // 3.14

// 数字转字符串
int g = 456;
String gStr = g.toString();  // "456"
String hStr = 3.14159.toStringAsFixed(2);  // "3.14"

数值运算

int a = 10;
int b = 3;

print(a + b);   // 13
print(a - b);   // 7
print(a * b);   // 30
print(a / b);   // 3.3333333333333335(返回double)
print(a ~/ b);  // 3(整除,返回int)
print(a % b);   // 1(取余)

6. 布尔类型

bool 类型只有两个值:truefalse

基本使用

bool isActive = true;
bool isFinished = false;

// 布尔表达式
bool isEven = 10 % 2 == 0;  // true
bool isGreater = 5 > 3;      // true

重要:Dart的类型安全

// 在Java中,这可以运行
// if (1) { }  // ❌ Dart中不行!

// 在Dart中,必须使用明确的布尔值
int count = 5;
if (count > 0) {  // ✅ 正确:必须是比较表达式
  print("count大于0");
}

// 检查空值
String? name;
if (name != null) {  // ✅ 必须明确检查null
  print(name.length);
}

// 简化写法(如果name不为null,才执行)
print(name?.length);  // 安全调用运算符

7. 列表类型 - List

List相当于Java中的ArrayList,但功能更丰富。

创建List

// 方式1:字面量创建
List<int> numbers = [1, 2, 3, 4, 5];
var fruits = ['苹果', '香蕉', '橙子'];  // 类型推断为List<String>

// 方式2:空列表
List<String> empty = [];  // 推荐
var empty2 = <String>[];  // 也推荐,明确泛型类型

// 方式3:填充创建
var zeros = List.filled(5, 0);  // [0, 0, 0, 0, 0]
var list = List.generate(5, (index) => index * 2);  // [0, 2, 4, 6, 8]

// 方式4:不可变List
const constList = [1, 2, 3];  // 编译时常量,不可修改

常用操作

var list = [1, 2, 3];

// 添加元素
list.add(4);           // [1, 2, 3, 4]
list.addAll([5, 6]);   // [1, 2, 3, 4, 5, 6]
list.insert(0, 0);     // 在索引0插入0:[0, 1, 2, 3, 4, 5, 6]
list.insertAll(2, [7, 8]);  // [0, 1, 7, 8, 2, 3, 4, 5, 6]

// 删除元素
list.remove(7);        // 删除值为7的元素
list.removeAt(0);      // 删除索引0的元素
list.removeLast();     // 删除最后一个
list.removeRange(1, 3); // 删除索引1到2的元素

// 查询元素
print(list[0]);        // 通过索引访问
print(list.indexOf(5)); // 查找元素索引
print(list.contains(3)); // 是否包含
print(list.length);    // 长度
print(list.isEmpty);   // 是否为空
print(list.isNotEmpty);// 是否不为空

高级特性

var list = [1, 2, 3, 4, 5];

// 扩展运算符(spread operator)
var list2 = [0, ...list];  // [0, 1, 2, 3, 4, 5]

// 空感知扩展
List<int>? nullableList;
var list3 = [1, 2, ...?nullableList];  // [1, 2](不会因为null崩溃)

// 集合中的if(条件添加)
var isActive = true;
var list4 = [
  1, 
  2,
  if (isActive) 3,  // 如果isActive为true,才添加3
];  // [1, 2, 3]

// 集合中的for(循环添加)
var list5 = [
  0,
  for (var i = 1; i <= 3; i++) i,  // 添加1,2,3
];  // [0, 1, 2, 3]

8. 字典类型 - Map

Map是键值对集合,类似Java的HashMap。

创建Map

// 方式1:字面量创建
Map<String, int> scores = {
  '张三': 90,
  '李四': 85,
  '王五': 88
};

// 类型推断
var map = {
  'name': '张三',
  'age': 25,
  'score': 95.5
};  // 推断为Map<String, Object>

// 方式2:构造器创建
var emptyMap = {};  // 注意:这是Map,不是Set!
var map2 = Map<String, int>();
var map3 = Map.from({'a': 1, 'b': 2});

// 方式3:不可变Map
const constMap = {'a': 1, 'b': 2};

常用操作

var map = {'name': '张三', 'age': 25};

// 添加/修改元素
map['score'] = 95;      // 添加新键值对
map['age'] = 26;        // 修改已有键的值
map.addAll({'city': '北京', 'gender': '男'});

// 获取元素
print(map['name']);      // 张三(如果键不存在返回null)
print(map['weight']);    // null(键不存在)

// 安全获取
var name = map['name'] ?? '未知';  // 如果为null,使用默认值
var weight = map['weight'] ?? 60;  // 60

// 删除元素
map.remove('age');       // 删除age键
map.clear();             // 清空所有

// 遍历Map
map.forEach((key, value) {
  print('$key: $value');
});

// 获取所有键或值
var keys = map.keys;      // Iterable<String>
var values = map.values;  // Iterable<Object>

高级特性

// Map中的if和for(类似List)
var condition = true;
var map = {
  'a': 1,
  'b': 2,
  if (condition) 'c': 3,  // 条件添加
  for (var i = 4; i <= 5; i++) 'key$i': i,  // 循环添加
};  // {'a': 1, 'b': 2, 'c': 3, 'key4': 4, 'key5': 5}

// 扩展合并Map
var map1 = {'a': 1, 'b': 2};
var map2 = {'b': 3, 'c': 4};
var merge = {...map1, ...map2};  // {'a': 1, 'b': 3, 'c': 4}

9. 动态类型 - dynamic

dynamic 是Dart的特殊类型,可以绕过类型检查。

基本使用

dynamic variable = "hello";
print(variable.length);  // 5(String的length属性)

variable = 123;
print(variable.isEven);  // false(int的isEven属性)

variable = true;
// print(variable.length);  // 运行时错误!布尔没有length属性

// 对比:使用Object
Object obj = "hello";
// obj.length;  // 编译错误!Object没有length属性

使用场景

// 场景1:与JSON交互
dynamic jsonData = jsonDecode('{"name":"张三","age":25}');
print(jsonData['name']);  // 运行时才知道类型

// 场景2:混合类型集合(不推荐)
List<dynamic> mixed = [1, "hello", true, [1, 2, 3]];

// 场景3:泛型不确定时
T genericMethod<T>(T value) {
  return value;
}

风险与注意事项

dynamic a = "123";
int b = a + 1;  // ❌ 运行时错误:字符串不能加数字

// 更好的做法:使用类型检查
if (a is String) {
  print(int.parse(a) + 1);  // 124
}

10. 空安全机制

Dart 2.12+ 引入空安全,是语言最重要的特性之一。

可空类型和非空类型

// 默认不可空
String name = "张三";  // 不能赋值为null
// name = null;  // ❌ 编译错误

// 可空类型:在类型后加?
String? nullableName;  // 可以是String或null
nullableName = null;   // ✅ 允许
nullableName = "李四";  // ✅ 允许

// 基本类型也是对象,同样遵循空安全
int? age;
double? height;
bool? isActive;

访问可空变量

String? name;

// 方法1:先判断再使用
if (name != null) {
  print(name.length);  // 自动推断为非空
}

// 方法2:安全调用运算符 ?.
print(name?.length);   // 如果name为null,返回null,不会崩溃

// 方法3:提供默认值 ??
var length = name?.length ?? 0;  // 如果name?.length为null,使用0

// 方法4:强制非空断言!(确定一定不为null时才用)
String? maybeName = getName();
if (someCondition) {
  print(maybeName!.length);  // 告诉编译器:我确定它不为null
}

延迟初始化

// late关键字:延迟初始化
class Person {
  late String name;  // 稍后初始化,使用前必须赋值

  void setName(String newName) {
    name = newName;  // 可以在这里初始化
  }
}

// 使用场景:依赖注入
class Database {
  late DatabaseConnection connection;

  void connect() {
    connection = DatabaseConnection();
  }
}

// 使用场景:循环引用
class A {
  late B b;
}

class B {
  late A a;
}

类型提升

String? nullableString = getString();

// Dart会自动进行类型提升
if (nullableString != null) {
  // 在这里nullableString被提升为非空类型
  print(nullableString.length);  // 不需要?或!
}

// 逻辑运算符也会触发类型提升
if (nullableString is String) {
  print(nullableString.length);  // 自动提升
}

11. 算数运算符和赋值运算符

算数运算符

int a = 10;
int b = 3;

print(a + b);   // 13
print(a - b);   // 7
print(a * b);   // 30
print(a / b);   // 3.3333333333333335
print(a ~/ b);  // 3(整除,Dart特有)
print(a % b);   // 1
print(-a);      // -10(一元负号)

// 自增自减
int c = 5;
print(c++);  // 5(先使用,后增加)
print(++c);  // 7(先增加,后使用)
print(c--);  // 7(先使用,后减少)
print(--c);  // 5(先减少,后使用)

赋值运算符

// 基本赋值
int a = 10;

// 复合赋值
a += 5;   // a = a + 5
a -= 3;   // a = a - 3
a *= 2;   // a = a * 2
a ~/= 3;  // a = a ~/ 3(整除)
a %= 4;   // a = a % 4

// 空赋值运算符 ??=
String? name;
name ??= "张三";  // 如果name为null,赋值为"张三"
print(name);     // 张三

name ??= "李四";  // name不为null,不赋值
print(name);     // 还是张三

与Java对比

Dart特有的运算符:

  • ~/:整除运算符
  • ??=:空赋值运算符

12. 比较运算符和逻辑运算符

比较运算符

int a = 5;
int b = 3;

print(a == b);   // false(相等)
print(a != b);   // true(不等)
print(a > b);    // true(大于)
print(a < b);    // false(小于)
print(a >= b);   // true(大于等于)
print(a <= b);   // false(小于等于)

// 注意:Dart中比较对象内容
var list1 = [1, 2, 3];
var list2 = [1, 2, 3];
print(list1 == list2);  // false(不同对象)
print(list1.hashCode == list2.hashCode);  // false

// 要比较内容,需要自己实现或使用特定方法

类型判断运算符

var value = "hello";

// is 判断类型
print(value is String);    // true
print(value is int);       // false
print(value is! int);      // true(不是int)

// 类型转换
if (value is String) {
  // 这里value自动转为String类型
  print(value.length);  // 可以直接调用String的方法
}

逻辑运算符

bool isSunny = true;
bool isWarm = false;

// 与运算 &&
print(isSunny && isWarm);  // false

// 或运算 ||
print(isSunny || isWarm);  // true

// 非运算 !
print(!isSunny);  // false
print(!isWarm);   // true

// 短路特性
var list;
print(list != null && list.isNotEmpty);  // 如果list为null,不会执行后面的判断

13. if分支和三元运算符

if-else语句

int score = 85;

// 基本if
if (score >= 60) {
  print("及格");
}

// if-else
if (score >= 90) {
  print("优秀");
} else {
  print("继续努力");
}

// if-else if-else
if (score >= 90) {
  print("A");
} else if (score >= 80) {
  print("B");
} else if (score >= 70) {
  print("C");
} else if (score >= 60) {
  print("D");
} else {
  print("F");
}

三元运算符

int age = 20;

// 基本用法
String status = age >= 18 ? "成年" : "未成年";
print(status);  // 成年

// 嵌套使用(不推荐,影响可读性)
String result = age > 60 ? "老年" : (age > 30 ? "中年" : "青年");

// 结合空安全
String? name;
String displayName = name ?? "访客";  // 如果name为null,使用"访客"
String displayName2 = name != null ? name : "访客";  // 等价于上面

14. 开关 - Switch

Dart的switch支持更多类型,且更安全。

基本使用

String grade = "A";

switch (grade) {
  case "A":
    print("优秀");
    break;
  case "B":
    print("良好");
    break;
  case "C":
    print("及格");
    break;
  case "D":
  case "F":  // 多个case共用同一个代码块
    print("需要努力");
    break;
  default:
    print("无效成绩");
}

支持的类型

// 整数
int number = 2;
switch (number) {
  case 1:
    print("一");
    break;
  case 2:
    print("二");
    break;
}

// 字符串(Java 7+也支持)
String command = "start";
switch (command) {
  case "start":
  case "go":
    print("开始");
    break;
  case "stop":
    print("停止");
    break;
}

// 枚举
enum Color { red, green, blue }
Color color = Color.red;
switch (color) {
  case Color.red:
    print("红色");
    break;
  case Color.green:
    print("绿色");
    break;
  case Color.blue:
    print("蓝色");
    break;
}

重要特性:必须覆盖所有可能

enum Status { pending, completed, failed }

String getMessage(Status status) {
  // 如果枚举新增了值,这里会编译警告
  switch (status) {
    case Status.pending:
      return "处理中";
    case Status.completed:
      return "完成";
    case Status.failed:
      return "失败";
  }
  // 不需要default,因为已经覆盖了所有枚举值
}

15. While循环

while循环

// 先判断,后执行
int i = 0;
while (i < 5) {
  print("i = $i");
  i++;
}
// 输出:0,1,2,3,4

// 可能一次都不执行
int j = 10;
while (j < 5) {  // 条件为false,循环体不会执行
  print("这行不会打印");
}

do-while循环

// 先执行一次,再判断
int i = 0;
do {
  print("i = $i");
  i++;
} while (i < 5);
// 输出:0,1,2,3,4

// 至少执行一次
int j = 10;
do {
  print("至少打印一次");  // 会打印
} while (j < 5);

break和continue

// break:跳出整个循环
int i = 0;
while (i < 10) {
  if (i == 5) {
    break;  // i等于5时退出循环
  }
  print(i);
  i++;
}
// 输出:0,1,2,3,4

// continue:跳过本次循环
for (int j = 0; j < 10; j++) {
  if (j % 2 == 0) {
    continue;  // 跳过偶数
  }
  print(j);
}
// 输出:1,3,5,7,9

16. For循环

标准for循环

// 基本语法
for (int i = 0; i < 5; i++) {
  print("i = $i");
}

// 多个变量
for (int i = 0, j = 10; i < j; i++, j--) {
  print("i = $i, j = $j");
}

for-in循环(增强for循环)

// 遍历List
var list = [1, 2, 3, 4, 5];
for (var item in list) {
  print(item);
}

// 遍历Set
var set = {1, 2, 3};
for (var value in set) {
  print(value);
}

// 遍历Map的键值对
var map = {'a': 1, 'b': 2};
for (var entry in map.entries) {
  print('${entry.key}: ${entry.value}');
}

forEach方法

var list = [1, 2, 3];

// 使用匿名函数
list.forEach((item) {
  print(item);
});

// 使用箭头函数
list.forEach((item) => print(item));

// 使用方法引用
list.forEach(print);

集合中的for(Dart 2.3+)

// 在集合字面量中使用for
var list = [1, 2, 3];
var newList = [
  0,
  for (var i in list) i * 2,  // [2, 4, 6]
];  // [0, 2, 4, 6]

// 配合if使用
var condition = true;
var result = [
  for (var i = 1; i <= 3; i++)
    if (condition) i
    else i * 10,
];

17. 函数定义

Dart中函数是一等公民,可以赋值给变量、作为参数传递。

基本函数定义

// 无返回值
void sayHello() {
  print("Hello");
}

// 有返回值
int add(int a, int b) {
  return a + b;
}

// 返回值类型可省略(不推荐)
multiply(int a, int b) {
  return a * b;  // 自动推断返回类型为int
}

函数也是对象

// 函数可以赋值给变量
var fun = sayHello;
fun();  // 调用函数

// 函数可以作为参数
void execute(Function callback) {
  callback();
}

execute(sayHello);

// 函数可以作为返回值
Function getGreeting() {
  return () => print("Hello");
}

var greet = getGreeting();
greet();

参数类型

// 必需参数(必须按顺序传递)
void printInfo(String name, int age) {
  print("$name is $age years old");
}

// 调用时必须传递两个参数
printInfo("张三", 25);

箭头函数(简写)

// 当函数体只有一行表达式时
int add(int a, int b) => a + b;

// 等价于
int add(int a, int b) {
  return a + b;
}

// 多个表达式?不,箭头函数只能有一个表达式
// void test() => { print("a"); print("b"); }  // ❌ 错误

18. 函数必传参数和可选位置参数

Dart的函数参数分为:必传参数、可选位置参数、可选命名参数。

必传参数

// 所有参数默认都是必传的
void greet(String name, String message) {
  print("$name: $message");
}

// 调用时必须传递所有参数
greet("张三", "你好");
// greet("张三");  // ❌ 错误:缺少参数

可选位置参数 []

// 使用[]包裹的参数是可选的
void sayHello(String name, [String? title, String? greeting]) {
  var finalGreeting = greeting ?? "你好";
  if (title != null) {
    print("$title $name, $finalGreeting");
  } else {
    print("$name, $finalGreeting");
  }
}

// 调用方式
sayHello("张三");  // 只传必传参数
sayHello("李四", "先生");  // 传一个可选参数
sayHello("王五", "博士", "早上好");  // 传两个可选参数

// 可选参数可以有默认值
void log(String message, [String level = "INFO"]) {
  print("[$level] $message");
}

log("系统启动");  // [INFO] 系统启动
log("错误发生", "ERROR");  // [ERROR] 错误发生

注意事项

// 可选参数必须在必传参数之后
// void test([int a], int b)  // ❌ 错误:可选参数不能在必传参数前面

// 多个可选参数,调用时按顺序匹配
void example(int a, [int? b, int? c, int? d]) {
  print("a=$a, b=$b, c=$c, d=$d");
}

example(1);           // a=1, b=null, c=null, d=null
example(1, 2);        // a=1, b=2, c=null, d=null
example(1, 2, 3);     // a=1, b=2, c=3, d=null
example(1, 2, 3, 4);  // a=1, b=2, c=3, d=4

19. 函数的可选命名参数

命名参数是Dart的特色功能,让函数调用更具可读性。

基本用法 {}

// 使用{}包裹命名参数
void createUser({
  required String name,  // required表示必须传递
  int? age,              // 可选的命名参数
  String? city,
  String? job,
}) {
  print("创建用户:$name, $age岁, 来自$city, 职业$job");
}

// 调用时指定参数名
createUser(
  name: "张三",
  age: 25,
  city: "北京",
);

createUser(
  name: "李四",
  job: "工程师",
  // 可以不按定义顺序
);

默认值

void configure({
  String host = "localhost",
  int port = 8080,
  bool https = false,
}) {
  print("连接:${https ? 'https' : 'http'}://$host:$port");
}

// 使用默认值
configure();  // http://localhost:8080

// 覆盖某些默认值
configure(host: "example.com", https: true);  // https://example.com:8080
configure(port: 3000);  // http://localhost:3000

混合参数类型

// 可以混合使用:必传参数 + 命名参数
void search(String query, {
  int? limit,
  bool caseSensitive = false,
}) {
  print("搜索:$query, 限制:$limit, 区分大小写:$caseSensitive");
}

// 调用
search("dart");                    // 只传必传参数
search("flutter", limit: 10);       // 传必传+一个命名参数
search("java", caseSensitive: true); // 传必传+另一个命名参数
search("kotlin", limit: 5, caseSensitive: true); // 全部

位置参数 vs 命名参数

// 位置参数 - 适合参数少、意义明确的场景
void log(String message, [String level = "INFO"]) {
  print("[$level] $message");
}

// 命名参数 - 适合参数多、可选性强的场景
void showDialog({
  required String title,
  String? content,
  bool cancellable = true,
  VoidCallback? onConfirm,
  VoidCallback? onCancel,
}) {
  // 实现弹窗逻辑
}

// 调用时一目了然
showDialog(
  title: "确认删除",
  content: "确定要删除这个文件吗?",
  onConfirm: () => print("确认"),
  onCancel: () => print("取消"),
);

20. 匿名函数和箭头函数

匿名函数(Lambda表达式)

// 基本匿名函数
var list = [1, 2, 3, 4, 5];

// 使用匿名函数作为参数
list.forEach((item) {
  print(item * 2);
});

// 赋值给变量
var multiply = (int a, int b) {
  return a * b;
};
print(multiply(3, 4));  // 12

// 无参数匿名函数
var greet = () {
  print("Hello");
};
greet();

箭头函数(简洁写法)

// 当函数体只有一行表达式时
var add = (int a, int b) => a + b;

// 等价于
var add2 = (int a, int b) {
  return a + b;
};

// 在集合操作中非常有用
var numbers = [1, 2, 3, 4, 5];
var doubled = numbers.map((n) => n * 2).toList();  // [2, 4, 6, 8, 10]
var evenNumbers = numbers.where((n) => n % 2 == 0).toList();  // [2, 4]

// 返回布尔值的箭头函数
var isEmpty = (String s) => s.isEmpty;
print(isEmpty(""));  // true

闭包(Closure)

// 函数可以访问其定义时的作用域
Function makeCounter() {
  int count = 0;  // 这个变量被闭包捕获

  return () {
    count++;  // 每次调用都会修改同一个count
    return count;
  };
}

var counter = makeCounter();
print(counter());  // 1
print(counter());  // 2
print(counter());  // 3

// 另一个例子:函数工厂
Function makeAdder(int addBy) {
  return (int i) => i + addBy;  // addBy被闭包捕获
}

var add2 = makeAdder(2);
var add5 = makeAdder(5);

print(add2(3));  // 5
print(add5(3));  // 8

常用场景

// 1. 事件处理
button.onClick.listen((event) {
  print("按钮被点击");
});

// 2. 排序
var people = ['张三', '李四', '王五'];
people.sort((a, b) => a.length.compareTo(b.length));

// 3. 过滤和转换
var numbers = [1, 2, 3, 4, 5];
var result = numbers
    .where((n) => n > 2)        // 过滤
    .map((n) => n * 10)          // 转换
    .toList();                   // [30, 40, 50]

// 4. 异步回调
Future.delayed(Duration(seconds: 1), () {
  print("1秒后执行");
});

21. 类的定义

Dart是纯粹的面向对象语言,所有东西都是对象,所有对象都是类的实例。

基本类定义

class Person {
  // 属性
  String name = "";
  int age = 0;

  // 方法
  void sayHello() {
    print("大家好,我是$name,今年$age岁");
  }

  // getter
  bool get isAdult => age >= 18;

  // setter
  set setName(String newName) {
    name = newName;
  }
}

// 使用类
var person = Person();
person.name = "张三";
person.age = 25;
person.sayHello();  // 大家好,我是张三,今年25岁
print(person.isAdult);  // true

属性和方法的可见性

Dart没有public、protected、private关键字,使用下划线表示私有。

class BankAccount {
  // 公有属性(默认)
  String owner;

  // 私有属性(以_开头,仅在当前文件可见)
  double _balance = 0;

  BankAccount(this.owner);

  // 公有方法
  void deposit(double amount) {
    _balance += amount;
    _logTransaction("存款", amount);
  }

  double get balance => _balance;  // 只读getter

  // 私有方法
  void _logTransaction(String type, double amount) {
    print("[$type] $amount,当前余额:$_balance");
  }
}

var account = BankAccount("张三");
account.deposit(1000);
// print(account._balance);  // ❌ 错误:不能访问私有属性
// account._logTransaction("测试", 100);  // ❌ 错误:不能访问私有方法
print(account.balance);  // 1000 ✅ 通过getter访问

计算属性(getter/setter)

class Rectangle {
  double width;
  double height;

  Rectangle(this.width, this.height);

  // getter:计算面积
  double get area => width * height;

  // getter:计算周长
  double get perimeter => 2 * (width + height);

  // setter:通过面积反推宽度(保持高度不变)
  set area(double newArea) {
    width = newArea / height;
  }

  // 带验证的setter
  set setWidth(double value) {
    if (value <= 0) {
      throw ArgumentError("宽度必须大于0");
    }
    width = value;
  }
}

var rect = Rectangle(10, 5);
print(rect.area);  // 50(像属性一样访问)
print(rect.perimeter);  // 30

rect.area = 100;  // 通过setter设置
print(rect.width);  // 20(因为100/5=20)

静态成员

class MathUtils {
  // 静态常量
  static const double pi = 3.14159;

  // 静态方法
  static int add(int a, int b) => a + b;

  // 静态变量
  static int _instanceCount = 0;

  // 构造方法中计数
  MathUtils() {
    _instanceCount++;
  }

  // 静态getter
  static int get instanceCount => _instanceCount;
}

// 使用静态成员
print(MathUtils.pi);  // 3.14159
print(MathUtils.add(5, 3));  // 8

var utils1 = MathUtils();
var utils2 = MathUtils();
print(MathUtils.instanceCount);  // 2

22. 类的默认构造函数

构造函数在创建对象时自动调用,用于初始化对象。

基本构造函数

class Person {
  String name;
  int age;

  // 默认构造函数(与类同名)
  Person(String name, int age) {
    this.name = name;
    this.age = age;
    print("Person对象被创建");
  }
}

var p = Person("张三", 25);  // 输出:Person对象被创建
print(p.name);  // 张三

语法糖写法(最常用)

class Person {
  String name;
  int age;

  // 构造参数直接赋值给属性
  Person(this.name, this.age);

  // 甚至可以混合
  Person.withDefaultAge(this.name) : age = 18;
}

var p1 = Person("张三", 25);
var p2 = Person.withDefaultAge("李四");  // age=18

构造函数初始化列表

class Point {
  double x;
  double y;

  // 初始化列表:在构造函数体执行前初始化
  Point.fromJson(Map<String, double> json)
      : x = json['x'] ?? 0,
        y = json['y'] ?? 0 {
    print("Point初始化完成:($x, $y)");
  }

  // 使用assert验证参数
  Point(this.x, this.y) : assert(x >= 0), assert(y >= 0);

  // 重定向构造函数
  Point.origin() : this(0, 0);
}

var p = Point.fromJson({'x': 10.5});
print(p.x);  // 10.5
print(p.y);  // 0

初始化列表的高级用法

class Person {
  final String name;  // final属性必须在构造函数中初始化
  final int age;
  final String id;

  // 初始化列表可以:
  // 1. 初始化final变量
  // 2. 验证输入
  // 3. 重定向构造函数
  Person(this.name, this.age)
      : id = "P${DateTime.now().millisecondsSinceEpoch}",
        assert(age > 0, "年龄必须大于0") {
    print("创建用户:$name");
  }

  // 初始化列表可以调用方法
  Person.fromName(String name)
      : this(name, _getDefaultAge());  // 调用静态方法

  static int _getDefaultAge() => 18;
}

23. 类的命名构造函数

Dart支持多个构造函数,通过命名来区分。

基本命名构造函数

class Person {
  String name;
  int age;
  String? email;

  // 主构造函数
  Person(this.name, this.age);

  // 命名构造函数:创建未成年人
  Person.child(String name)
      : this.name = name,
        this.age = 10;

  // 命名构造函数:从JSON创建
  Person.fromJson(Map<String, dynamic> json)
      : name = json['name'],
        age = json['age'],
        email = json['email'];

  // 命名构造函数:创建默认用户
  Person.guest()
      : name = "访客",
        age = 0;

  void introduce() {
    print("我是$name,${age}岁${email != null ? ', 邮箱:$email' : ''}");
  }
}

// 使用不同的构造函数
var p1 = Person("张三", 25);
p1.introduce();  // 我是张三,25岁

var p2 = Person.child("小明");
p2.introduce();  // 我是小明,10岁

var p3 = Person.fromJson({
  'name': '李四',
  'age': 30,
  'email': 'lisi@example.com'
});
p3.introduce();  // 我是李四,30岁, 邮箱:lisi@example.com

var p4 = Person.guest();
p4.introduce();  // 我是访客,0岁

工厂构造函数

工厂构造函数不一定会创建新实例,可以返回缓存的对象或子类实例。

class Singleton {
  // 私有构造函数
  Singleton._internal();

  // 静态实例
  static final Singleton _instance = Singleton._internal();

  // 工厂构造函数
  factory Singleton() {
    return _instance;  // 总是返回同一个实例
  }
}

// 使用
var s1 = Singleton();
var s2 = Singleton();
print(identical(s1, s2));  // true(同一个对象)

更复杂的工厂构造函数示例

class Shape {
  // 工厂构造函数可以返回子类
  factory Shape(String type) {
    switch (type) {
      case 'circle':
        return Circle();
      case 'square':
        return Square();
      default:
        throw ArgumentError('Unknown shape type');
    }
  }
}

class Circle implements Shape {
  Circle();
}

class Square implements Shape {
  Square();
}

// 使用
var shape = Shape('circle');  // 实际得到的是Circle对象

24. 类的构造函数语法糖写法

Dart提供了多种简洁的构造函数写法。

最简写法:this.参数

class Point {
  double x;
  double y;

  // 最简洁的写法
  Point(this.x, this.y);

  // 等价于
  // Point(double x, double y) {
  //   this.x = x;
  //   this.y = y;
  // }
}

var p = Point(3, 4);

可选参数的构造函数

class Person {
  String name;
  int age;
  String? email;
  String? phone;

  // 组合使用:必传参数 + 可选命名参数
  Person(this.name, this.age, {this.email, this.phone});

  // 或者使用可选位置参数
  Person.withOptional(this.name, this.age, [this.email, this.phone]);

  @override
  String toString() {
    return "$name($age) $email $phone";
  }
}

// 调用
var p1 = Person("张三", 25);
var p2 = Person("李四", 30, email: "li@example.com");
var p3 = Person("王五", 28, email: "wang@ex.com", phone: "123456");
var p4 = Person.withOptional("赵六", 22, "zhao@ex.com");

初始化列表的语法糖

class Rectangle {
  final double width;
  final double height;
  late final double area;  // 稍后初始化

  // 初始化列表中可以执行表达式
  Rectangle(this.width, this.height) : area = width * height;

  // 重定向构造函数
  Rectangle.square(double size) : this(size, size);

  // 条件初始化
  Rectangle.fromWidth(double width) 
      : this(width, width * 0.618);  // 黄金比例
}

const构造函数

class ImmutablePoint {
  final double x;
  final double y;

  // const构造函数:所有属性必须是final
  const ImmutablePoint(this.x, this.y);

  // 常量构造函数不能有函数体
}

// 创建编译时常量
const origin = ImmutablePoint(0, 0);
const p1 = ImmutablePoint(1, 2);
const p2 = ImmutablePoint(1, 2);

print(identical(p1, p2));  // true(相同常量值复用同一对象)

更复杂的示例

class User {
  final String id;
  final String name;
  final int createdAt;
  String? avatar;
  List<String> roles;

  // 综合使用各种特性
  const User({
    required this.name,
    this.avatar,
    this.roles = const [],
  }) : id = _generateId(),
       createdAt = DateTime.now().millisecondsSinceEpoch;

  // 私有静态方法
  static String _generateId() {
    return DateTime.now().millisecondsSinceEpoch.toString();
  }

  // 命名构造函数 + 重定向
  User.admin(String name)
      : this(
          name: name,
          roles: ['admin'],
          avatar: 'default_admin.png',
        );

  // 工厂构造函数 + 缓存
  static final Map<String, User> _cache = {};

  factory User.fromCache(String id, String name) {
    if (_cache.containsKey(id)) {
      return _cache[id]!;
    } else {
      final user = User(name: name);
      _cache[id] = user;
      return user;
    }
  }
}

25. 类的公有属性和私有属性

Dart的访问控制基于文件级别,使用下划线_表示私有。

基本私有属性

// 文件:person.dart
class Person {
  // 公有属性
  String name;

  // 私有属性(仅当前文件可见)
  int _age;
  String _id;

  // 构造函数
  Person(this.name, this._age) : _id = _generateId();

  // 公有方法可以访问私有属性
  void introduce() {
    print("我是$name,年龄$_age,ID:$_id");
  }

  // getter提供只读访问
  int get age => _age;

  // setter可以添加验证
  set age(int value) {
    if (value < 0 || value > 150) {
      throw ArgumentError("年龄无效");
    }
    _age = value;
  }

  // 私有方法
  static String _generateId() {
    return DateTime.now().millisecondsSinceEpoch.toString();
  }
}

另一个文件使用

// 文件:main.dart
import 'person.dart';

void main() {
  var p = Person("张三", 25);

  // 可以访问公有属性和方法
  print(p.name);  // 张三
  p.introduce();  // 我是张三,年龄25,ID:...

  // 不能直接访问私有成员
  // print(p._age);  // ❌ 错误
  // p._generateId();  // ❌ 错误

  // 通过getter/setter访问
  print(p.age);  // 25
  p.age = 30;    // 通过setter修改
}

库级别的私有

// 文件:utils.dart
// 以下划线开头的顶级变量、函数也是私有的
String _secretKey = "123456";

void _privateFunction() {
  print("这是私有函数");
}

// 公开的类可以访问同一文件中的私有成员
class DataProcessor {
  void process() {
    print(_secretKey);  // ✅ 可以访问
    _privateFunction();  // ✅ 可以访问
  }
}

// 公开的函数
void publicFunction() {
  print("公开函数");
}

封装的实践

class BankAccount {
  // 私有属性
  String _accountNumber;
  double _balance = 0;
  List<String> _transactions = [];

  // 公开构造函数
  BankAccount(this._accountNumber);

  // 只读getter
  String get accountNumber => _accountNumber;
  double get balance => _balance;

  // 只读集合的副本(保护内部数据)
  List<String> get transactions => List.unmodifiable(_transactions);

  // 带验证的方法
  void deposit(double amount) {
    if (amount <= 0) {
      throw ArgumentError("存款金额必须大于0");
    }
    _balance += amount;
    _addTransaction("存款", amount);
  }

  bool withdraw(double amount) {
    if (amount <= 0) {
      throw ArgumentError("取款金额必须大于0");
    }
    if (amount > _balance) {
      return false;
    }
    _balance -= amount;
    _addTransaction("取款", amount);
    return true;
  }

  // 私有方法
  void _addTransaction(String type, double amount) {
    _transactions.add("$type: $amount,余额: $_balance");
  }
}

// 使用
var account = BankAccount("123456");
account.deposit(1000);
account.withdraw(500);
print(account.balance);  // 500
print(account.transactions);  // ["存款: 1000,余额: 1000", "取款: 500,余额: 500"]

// 不能修改内部数据
// account._balance = 10000;  // ❌ 错误
// account.transactions.add("非法操作");  // ❌ 错误(不可修改的集合)

26. 类的继承

Dart是单继承语言,使用extends关键字。

基本继承

class Animal {
  String name;

  Animal(this.name);

  void eat() {
    print("$name 在吃东西");
  }

  void sleep() {
    print("$name 在睡觉");
  }
}

class Dog extends Animal {
  // 调用父类构造函数
  Dog(String name) : super(name);

  // 子类特有方法
  void bark() {
    print("$name 在汪汪叫");
  }

  // 重写父类方法
  @override
  void eat() {
    super.eat();  // 调用父类方法
    print("$name 吃得特别香");
  }
}

void main() {
  var dog = Dog("旺财");
  dog.eat();     // 旺财在吃东西 → 旺财吃得特别香
  dog.sleep();   // 旺财在睡觉
  dog.bark();    // 旺财在汪汪叫
}

构造函数继承

class Person {
  String name;
  int age;

  Person(this.name, this.age);

  // 命名构造函数
  Person.guest() : name = "访客", age = 0;

  void introduce() {
    print("我是$name,$age岁");
  }
}

class Student extends Person {
  String school;

  // 必须调用父类构造函数
  Student(String name, int age, this.school) : super(name, age);

  // 调用父类命名构造函数
  Student.guest(String school) 
      : this.school = school,
        super.guest();

  // 调用父类构造函数 + 初始化列表
  Student.fromName(String name) 
      : school = "未知学校",
        super(name, 18);

  @override
  void introduce() {
    super.introduce();
    print("我在$school上学");
  }
}

方法重写的规则

class Parent {
  // 可重写的方法
  void normalMethod() {
    print("父类普通方法");
  }

  // 不可重写的方法(使用final)
  final void cannotOverride() {
    print("这个方法不能重写");
  }

  // 非虚方法(static不能被继承)
  static void staticMethod() {
    print("静态方法");
  }
}

class Child extends Parent {
  @override
  void normalMethod() {
    print("子类重写的方法");
  }

  // @override
  // void cannotOverride() {}  // ❌ 错误:不能重写final方法

  // @override
  // static void staticMethod() {}  // ❌ 错误:不能重写静态方法
}

类型检查和转换

class Animal {}
class Dog extends Animal {
  void bark() => print("汪汪");
}
class Cat extends Animal {
  void meow() => print("喵喵");
}

void main() {
  Animal animal = Dog();

  // is 检查类型
  print(animal is Dog);  // true
  print(animal is Cat);  // false

  // as 类型转换
  if (animal is Dog) {
    // 自动转换(is检查后自动提升)
    animal.bark();  // 可以直接调用Dog的方法
  }

  // 强制转换(不安全)
  var dog = animal as Dog;
  dog.bark();

  // 错误的转换会抛出异常
  // var cat = animal as Cat;  // ❌ 运行时错误
}

继承与组合的选择

// 继承:is-a关系
class Vehicle {
  void move() => print("移动");
}

class Car extends Vehicle {
  void honk() => print("按喇叭");
}

// 组合:has-a关系
class Engine {
  void start() => print("引擎启动");
}

class Bicycle {
  Engine? engine;  // 可选:自行车可能有引擎吗?

  void ride() => print("骑行");
}

27. 类的多态

多态允许使用父类类型的变量引用子类对象。

基本多态

abstract class Shape {
  double get area;

  void draw() {
    print("绘制形状");
  }
}

class Circle extends Shape {
  double radius;

  Circle(this.radius);

  @override
  double get area => 3.14 * radius * radius;

  @override
  void draw() {
    print("绘制圆形,半径:$radius");
  }

  void roll() {
    print("圆形可以滚动");
  }
}

class Square extends Shape {
  double side;

  Square(this.side);

  @override
  double get area => side * side;

  @override
  void draw() {
    print("绘制正方形,边长:$side");
  }
}

void main() {
  // 多态:使用父类类型
  Shape shape1 = Circle(5);
  Shape shape2 = Square(4);

  // 调用重写的方法
  shape1.draw();  // 绘制圆形
  shape2.draw();  // 绘制正方形

  // 访问属性
  print(shape1.area);  // 78.5
  print(shape2.area);  // 16

  // 不能调用子类特有方法
  // shape1.roll();  // ❌ 错误

  // 如果需要调用子类方法,需要类型转换
  if (shape1 is Circle) {
    shape1.roll();  // ✅ is检查后自动转换
  }
}

参数多态

// 方法参数使用父类类型,可以接收任何子类对象
void printArea(Shape shape) {
  print("面积:${shape.area}");
  shape.draw();
}

void main() {
  printArea(Circle(5));
  printArea(Square(4));
}

// 集合多态
List<Shape> shapes = [
  Circle(3),
  Square(5),
  Circle(2),
];

// 遍历集合
shapes.forEach((shape) {
  print(shape.area);
});

运行时类型信息

void processShape(Shape shape) {
  // 获取运行时类型
  print(shape.runtimeType);  // Circle 或 Square

  // 类型判断
  if (shape is Circle) {
    // 在这里可以访问Circle的特有方法
    shape.roll();
  } else if (shape is Square) {
    // Square特有的处理
    print("正方形对角线:${shape.side * 1.414}");
  }
}

多态的实际应用

// 策略模式
abstract class PaymentStrategy {
  void pay(double amount);
}

class CreditCardPayment implements PaymentStrategy {
  String cardNumber;

  CreditCardPayment(this.cardNumber);

  @override
  void pay(double amount) {
    print("使用信用卡 $cardNumber 支付 $amount 元");
  }
}

class AlipayPayment implements PaymentStrategy {
  String account;

  AlipayPayment(this.account);

  @override
  void pay(double amount) {
    print("使用支付宝 $account 支付 $amount 元");
  }
}

class ShoppingCart {
  List<double> items = [];

  void checkout(PaymentStrategy payment) {
    double total = items.reduce((a, b) => a + b);
    payment.pay(total);
  }
}

// 使用
var cart = ShoppingCart();
cart.items = [100, 200, 50];

// 可以轻松切换支付方式
cart.checkout(CreditCardPayment("1234-5678"));
cart.checkout(AlipayPayment("user@example.com"));

多态与工厂模式

// 工厂模式结合多态
class ShapeFactory {
  static Shape createShape(String type, double size) {
    switch (type) {
      case 'circle':
        return Circle(size);
      case 'square':
        return Square(size);
      default:
        throw ArgumentError('Unknown shape type');
    }
  }
}

// 客户端代码不知道具体类型
List<Shape> createShapes() {
  return [
    ShapeFactory.createShape('circle', 5),
    ShapeFactory.createShape('square', 4),
    ShapeFactory.createShape('circle', 3),
  ];
}

// 所有形状都可以统一处理
void main() {
  var shapes = createShapes();
  shapes.forEach((shape) {
    print("面积:${shape.area}");
  });
}

28. 类的抽象和接口

Dart中抽象类和接口的概念与其他语言略有不同。

抽象类

使用abstract关键字定义抽象类,可以包含抽象方法和具体方法。

abstract class Animal {
  // 抽象属性
  String name;

  // 构造函数(抽象类可以有构造函数)
  Animal(this.name);

  // 抽象方法
  void makeSound();

  // 具体方法
  void sleep() {
    print("$name 在睡觉");
  }

  // 抽象getter
  int get legCount;
}

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

  @override
  void makeSound() {
    print("$name 汪汪叫");
  }

  @override
  int get legCount => 4;
}

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

  @override
  void makeSound() {
    print("$name 叽叽喳喳");
  }

  @override
  int get legCount => 2;
}

// 不能实例化抽象类
// var animal = Animal("动物");  // ❌ 错误

var dog = Dog("旺财");
dog.makeSound();  // 旺财汪汪叫
dog.sleep();      // 旺财在睡觉
print(dog.legCount);  // 4

接口(Implicit interfaces)

Dart中没有interface关键字,每个类都隐式定义了一个接口。

// 这个类同时也是一个接口
class Flyable {
  void fly() {
    print("飞行中");
  }

  void land() {
    print("降落");
  }
}

// 使用implements实现接口
class Bird implements Flyable {
  @override
  void fly() {
    print("小鸟在飞");
  }

  @override
  void land() {
    print("小鸟降落");
  }
}

// 可以实现多个接口
class Swimmable {
  void swim() {
    print("游泳中");
  }
}

class Duck implements Flyable, Swimmable {
  @override
  void fly() {
    print("鸭子飞");
  }

  @override
  void land() {
    print("鸭子降落");
  }

  @override
  void swim() {
    print("鸭子游泳");
  }
}

抽象类 vs 接口

// 抽象类:提供部分实现
abstract class Database {
  // 抽象方法
  void connect();
  void disconnect();

  // 具体方法
  void executeQuery(String sql) {
    connect();
    print("执行SQL: $sql");
    disconnect();
  }
}

class MySQL extends Database {
  @override
  void connect() {
    print("连接MySQL数据库");
  }

  @override
  void disconnect() {
    print("断开MySQL连接");
  }
}

// 接口:只定义规范
class JsonSerializable {
  Map<String, dynamic> toJson();
  void fromJson(Map<String, dynamic> json);
}

class User implements JsonSerializable {
  String name;
  int age;

  User(this.name, this.age);

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

  @override
  void fromJson(Map<String, dynamic> json) {
    name = json['name'];
    age = json['age'];
  }
}

实际应用示例

// 定义多个接口
abstract class Drawable {
  void draw();
}

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

abstract class Colorable {
  void setColor(String color);
}

// 类可以实现多个接口
class Rectangle implements Drawable, Resizable, Colorable {
  double width;
  double height;
  String color = "black";

  Rectangle(this.width, this.height);

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

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

  @override
  void setColor(String color) {
    this.color = color;
  }
}

// 另一个类只实现部分接口
class Text implements Drawable {
  String content;

  Text(this.content);

  @override
  void draw() {
    print("绘制文本: $content");
  }
}

接口的默认实现

// 可以提供默认实现
class Logger {
  void log(String message) {
    print("LOG: $message");
  }

  void error(String message) {
    print("ERROR: $message");
  }
}

// 如果只想要接口,不想继承实现,使用implements
class FileLogger implements Logger {
  @override
  void log(String message) {
    // 必须自己实现所有方法
    print("File: $message");
  }

  @override
  void error(String message) {
    print("File Error: $message");
  }
}

// 如果想复用实现,使用extends
class ConsoleLogger extends Logger {
  // 自动继承log和error的实现
  // 可以重写需要的方法
  @override
  void log(String message) {
    print("Console: $message");
  }
}

29. 类的混入

Mixin是Dart中代码复用的强大特性,可以实现类似多继承的效果。

基本Mixin

使用mixin关键字定义,用with关键字使用。

mixin Flyable {
  void fly() {
    print("飞行中");
  }

  void land() {
    print("降落");
  }
}

mixin Swimmable {
  void swim() {
    print("游泳中");
  }

  void dive() {
    print("潜水");
  }
}

class Bird with Flyable {
  String name;

  Bird(this.name);

  void chirp() {
    print("$name 叽叽喳喳");
  }
}

class Duck with Flyable, Swimmable {
  String name;

  Duck(this.name);

  @override
  void fly() {
    print("$name 在飞");
  }
}

void main() {
  var bird = Bird("小鸟");
  bird.fly();     // 飞行中
  bird.chirp();   // 小鸟叽叽喳喳

  var duck = Duck("鸭子");
  duck.fly();     // 鸭子 在飞
  duck.swim();    // 游泳中
  duck.dive();    // 潜水
}

Mixin的限制和特性

// Mixin不能有构造函数
mixin Playable {
  // ❌ 不能有构造函数
  // Playable() {}

  // 可以有属性
  String game = "默认游戏";

  // 可以有方法
  void play() {
    print("玩$game");
  }

  // 可以有抽象方法
  void stop();
}

class Child with Playable {
  @override
  void stop() {
    print("停止游戏");
  }
}

// Mixin可以指定类型约束(只能用于特定类的子类)
mixin Walkable on Animal {
  void walk() {
    print("$name 在走路");
  }
}

class Animal {
  String name;
  Animal(this.name);
}

class Person extends Animal with Walkable {
  Person(String name) : super(name);
}

// ❌ Dog没有继承Animal,不能使用Walkable
// class Dog with Walkable {}  // 错误

解决命名冲突

mixin A {
  void test() {
    print("A的test");
  }
}

mixin B {
  void test() {
    print("B的test");
  }
}

// 后混入的覆盖前面的
class C with A, B {
  // 使用的是B的test
}

class D with B, A {
  // 使用的是A的test
}

class E with A, B {
  @override
  void test() {
    print("自己的test");
    super.test();  // 调用的是B的test(最后一个混入的)
  }
}

void main() {
  C().test();  // B的test
  D().test();  // A的test
  E().test();  // 自己的test → B的test
}

实际应用场景

// 1. 日志功能混入
mixin Logger {
  void log(String message) {
    var time = DateTime.now().toString().substring(0, 19);
    print("[$time] $message");
  }

  void error(String message) {
    log("ERROR: $message");
  }
}

class UserService with Logger {
  void createUser(String name) {
    log("创建用户: $name");
    // 业务逻辑...
    log("用户创建成功");
  }
}

// 2. 验证功能混入
mixin Validator {
  bool isEmail(String value) {
    return value.contains('@') && value.contains('.');
  }

  bool isPhone(String value) {
    return value.length == 11 && value.startsWith('1');
  }

  bool notEmpty(String value) {
    return value.isNotEmpty;
  }
}

class RegisterForm with Validator {
  String email = "";
  String phone = "";

  bool validate() {
    if (!notEmpty(email)) {
      error("邮箱不能为空");
      return false;
    }
    if (!isEmail(email)) {
      error("邮箱格式不正确");
      return false;
    }
    return true;
  }

  void error(String msg) => print(msg);
}

// 3. 缓存功能混入
mixin Cacheable<T> {
  Map<String, T> _cache = {};

  T? getFromCache(String key) {
    return _cache[key];
  }

  void addToCache(String key, T value) {
    _cache[key] = value;
    print("已缓存: $key");
  }

  void clearCache() {
    _cache.clear();
  }
}

class DataRepository with Cacheable<Map<String, dynamic>> {
  Future<Map<String, dynamic>> fetchData(String id) {
    // 先查缓存
    var cached = getFromCache(id);
    if (cached != null) {
      return Future.value(cached);
    }

    // 模拟网络请求
    return Future.delayed(Duration(seconds: 1), () {
      var data = {'id': id, 'name': '数据$id'};
      addToCache(id, data);
      return data;
    });
  }
}

Mixin vs 继承 vs 接口

// 继承:is-a关系
class Vehicle {
  void move() => print("移动");
}

class Car extends Vehicle {
  void honk() => print("鸣笛");
}

// 接口:can-do关系
mixin Drivable {
  void drive();
}

mixin Parkable {
  void park();
}

// Mixin:has-feature关系
class Tesla extends Vehicle with Drivable, Parkable {
  @override
  void drive() {
    print("自动驾驶");
  }

  @override
  void park() {
    print("自动泊车");
  }
}

30. 泛型

泛型允许类、接口和方法在定义时使用类型参数,提高代码复用性和类型安全性。

泛型类

// 简单的泛型类
class Box<T> {
  T value;

  Box(this.value);

  T getValue() => value;

  void setValue(T newValue) {
    value = newValue;
  }
}

// 使用
var intBox = Box<int>(123);
print(intBox.getValue());  // 123
// intBox.setValue("hello");  // ❌ 类型错误

var stringBox = Box<String>("Hello");
print(stringBox.getValue());  // Hello

// 类型推断
var autoBox = Box("自动推断");  // Box<String>

多个类型参数

class Pair<K, V> {
  K key;
  V value;

  Pair(this.key, this.value);

  @override
  String toString() => "Pair($key: $value)";

  // 泛型方法
  Pair<U, V> mapKey<U>(U Function(K) transform) {
    return Pair(transform(key), value);
  }
}

// 使用
var pair = Pair<String, int>("age", 25);
print(pair);  // Pair(age: 25)

var mapped = pair.mapKey((key) => key.length);
print(mapped);  // Pair(3: 25)

泛型约束

// 限制类型参数必须是某个类的子类
class NumberBox<T extends num> {
  T value;

  NumberBox(this.value);

  double get squared => value * value;  // 可以调用num的方法
}

// 正确
var intBox = NumberBox<int>(5);
var doubleBox = NumberBox<double>(3.14);

// 错误
// var stringBox = NumberBox<String>("hello");  // ❌ 编译错误

// 多约束
class MyClass<T extends Object> {
  // T必须是非空类型
}

// 接口约束
mixin Flyable {}

class Bird with Flyable {}

class Cage<T extends Flyable> {
  T animal;

  Cage(this.animal);
}

// 正确
var cage = Cage(Bird());

// 错误
// var cage2 = Cage(Object());  // ❌

泛型方法

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

// 使用
var numbers = [1, 2, 3];
var firstNumber = first<int>(numbers);  // 1
// 类型推断
var firstString = first(["a", "b", "c"]);  // "a"

// 泛型工具函数
List<T> filter<T>(List<T> items, bool Function(T) predicate) {
  var result = <T>[];
  for (var item in items) {
    if (predicate(item)) {
      result.add(item);
    }
  }
  return result;
}

// 使用
var evens = filter<int>([1, 2, 3, 4, 5], (n) => n % 2 == 0);
print(evens);  // [2, 4]

泛型与集合

// List
List<int> numbers = [1, 2, 3];
var strings = <String>["a", "b"];  // 另一种写法

// Set
Set<int> uniqueNumbers = {1, 2, 3};
var uniqueStrings = <String>{"a", "b"};

// Map
Map<String, int> scores = {"张三": 90, "李四": 85};
var map = <String, dynamic>{"name": "张三", "age": 25};

// 泛型集合操作
List<int> list1 = [1, 2, 3];
List<int> list2 = [4, 5, 6];
List<int> combined = [...list1, ...list2];

var doubled = list1.map((n) => n * 2).toList();  // [2, 4, 6]
var sum = list1.reduce((a, b) => a + b);  // 6

泛型的高级用法

// 类型安全的建造者模式
class Builder<T> {
  T? _value;

  Builder<T> withValue(T value) {
    _value = value;
    return this;
  }

  T build() {
    if (_value == null) {
      throw StateError("Value not set");
    }
    return _value!;
  }
}

// 泛型单例工厂
class Singleton<T> {
  static final Map<Type, Object> _instances = {};

  factory Singleton(T instance) {
    var type = T;
    if (!_instances.containsKey(type)) {
      _instances[type] = instance;
    }
    return Singleton._internal();
  }

  Singleton._internal();

  T? get() => _instances[T] as T?;
}

// 泛型缓存
class Cache<T> {
  final Map<String, T> _cache = {};

  T? get(String key) => _cache[key];

  void set(String key, T value) {
    _cache[key] = value;
  }

  void clear() => _cache.clear();

  List<T> getAll() => _cache.values.toList();
}

泛型与类型系统

// 协变
class Animal {}
class Dog extends Animal {}

List<Animal> animals = <Dog>[];  // ✅ Dart支持协变

// 类型通配符(类似Java的?)
void printList(List<Object> list) {
  print(list);
}

// 可以使用List<dynamic>
var strings = <String>["a", "b"];
printList(strings);  // ✅ 可以

// 类型检查
void checkType<T>(T value) {
  print(value is T);  // true
  print(value.runtimeType);  // 实际类型
}

// 泛型函数类型
typedef Mapper<S, T> = T Function(S source);

List<T> mapList<S, T>(List<S> list, Mapper<S, T> mapper) {
  return list.map(mapper).toList();
}

// 使用
var ints = [1, 2, 3];
var strings2 = mapList<int, String>(ints, (i) => "数字$i");
print(strings2);  // [数字1, 数字2, 数字3]

31. 异步编程

Dart是单线程模型,但通过事件循环支持异步操作。

异步基础

// 同步代码会阻塞
void slowOperation() {
  sleep(Duration(seconds: 2));  // 阻塞2秒
  print("操作完成");
}

// 异步代码不会阻塞
Future<void> asyncOperation() async {
  await Future.delayed(Duration(seconds: 2));  // 非阻塞等待
  print("异步操作完成");
}

void main() {
  print("开始");
  asyncOperation();
  print("结束");
  // 输出顺序:
  // 开始
  // 结束
  // (2秒后) 异步操作完成
}

事件循环

import 'dart:async';

void demonstrateEventLoop() {
  print("1. 同步代码");

  Future(() => print("2. 微任务队列外的Future"));

  scheduleMicrotask(() => print("3. 微任务"));

  Future.delayed(Duration.zero, () => print("4. 延迟Future"));

  Future.microtask(() => print("5. 微任务Future"));

  print("6. 更多同步代码");
}

// 输出顺序:
// 1. 同步代码
// 6. 更多同步代码
// 3. 微任务
// 5. 微任务Future
// 2. 微任务队列外的Future
// 4. 延迟Future

常见异步场景

// 1. 网络请求
Future<String> fetchData() async {
  await Future.delayed(Duration(seconds: 1));
  return "数据";
}

// 2. 文件操作
import 'dart:io';

Future<void> readFile() async {
  var file = File('test.txt');
  if (await file.exists()) {
    var content = await file.readAsString();
    print(content);
  }
}

// 3. 定时器
Timer.periodic(Duration(seconds: 1), (timer) {
  print("每秒执行一次");
  if (/*某个条件*/) {
    timer.cancel();
  }
});

// 4. 流式数据
Stream<int> countStream(int max) async* {
  for (int i = 1; i <= max; i++) {
    await Future.delayed(Duration(milliseconds: 500));
    yield i;  // 发射数据
  }
}

错误处理

Future<void> asyncWithError() async {
  try {
    var result = await riskyOperation();
    print("成功: $result");
  } on TimeoutException catch (e) {
    print("超时: $e");
  } catch (e, stackTrace) {
    print("其他错误: $e");
    print(stackTrace);
  } finally {
    print("清理资源");
  }
}

// 或者使用catchError
riskyOperation()
    .then((value) => print("成功: $value"))
    .catchError((error) => print("错误: $error"))
    .whenComplete(() => print("完成"));

32. Future基本使用

Future表示一个异步操作的结果,类似于Java的Future/CompletableFuture。

创建Future

// 1. 直接创建已完成的值
Future.value(42).then((v) => print(v));

// 2. 创建错误
Future.error("出错了").catchError((e) => print(e));

// 3. 延迟执行
Future.delayed(Duration(seconds: 1), () {
  return "1秒后返回";
}).then((msg) => print(msg));

// 4. 异步函数自动返回Future
Future<String> fetchData() {
  return Future(() {
    // 耗时操作
    return "数据";
  });
}

// 5. 使用async标记
Future<String> fetchDataAsync() async {
  await Future.delayed(Duration(seconds: 1));
  return "数据";
}

Future的状态

void checkFutureStates() {
  // 未完成
  var future1 = Future.delayed(Duration(seconds: 1), () => "完成");

  // 已完成(有值)
  var future2 = Future.value("已有值");

  // 已完成(有错误)
  var future3 = Future.error(Exception("错误"));

  // 检查状态
  future2.then((value) {
    print("已完成: $value");
  }).catchError((e) {
    print("错误: $e");
  });
}

Future的常用方法

void futureMethods() {
  // then - 处理成功结果
  Future.value(10)
      .then((value) => value * 2)
      .then((value) => print(value));  // 20

  // catchError - 处理错误
  Future.error("错误")
      .catchError((e) => "已恢复")
      .then((v) => print(v));  // 已恢复

  // whenComplete - 无论成功失败都会执行
  Future.delayed(Duration(seconds: 1))
      .whenComplete(() => print("完成"));

  // timeout - 超时处理
  Future.delayed(Duration(seconds: 3))
      .timeout(Duration(seconds: 2), onTimeout: () {
        print("超时");
        return null;
      });
}

等待多个Future

void multipleFutures() {
  Future<String> fetchUser() async {
    await Future.delayed(Duration(seconds: 1));
    return "张三";
  }

  Future<int> fetchAge() async {
    await Future.delayed(Duration(seconds: 2));
    return 25;
  }

  // Future.wait - 等待所有完成
  Future.wait([fetchUser(), fetchAge()])
      .then((results) {
        print("用户: ${results[0]}, 年龄: ${results[1]}");
      });

  // Future.any - 只要有一个完成
  Future.any([fetchUser(), fetchAge()])
      .then((first) => print("最先完成: $first"));

  // Future.doWhile - 循环执行
  int count = 0;
  Future.doWhile(() async {
    if (count < 3) {
      await Future.delayed(Duration(seconds: 1));
      print("计数: ${++count}");
      return true;  // 继续循环
    }
    return false;  // 停止循环
  });
}

实际应用示例

class UserService {
  Future<Map<String, dynamic>> fetchUser(int id) async {
    // 模拟网络请求
    await Future.delayed(Duration(seconds: 1));

    if (id <= 0) {
      throw Exception("无效的用户ID");
    }

    return {
      'id': id,
      'name': '用户$id',
      'age': 20 + id,
    };
  }

  Future<void> processUser() async {
    try {
      var user = await fetchUser(123);
      print("获取用户成功: $user");
    } catch (e) {
      print("获取用户失败: $e");
    }
  }
}

33. Future链式调用

Future的链式调用可以优雅地处理多个异步操作。

基本链式调用

void basicChaining() {
  Future<String> step1() async {
    await Future.delayed(Duration(seconds: 1));
    return "步骤1结果";
  }

  Future<String> step2(String input) async {
    await Future.delayed(Duration(seconds: 1));
    return "$input → 步骤2结果";
  }

  Future<String> step3(String input) async {
    await Future.delayed(Duration(seconds: 1));
    return "$input → 步骤3结果";
  }

  // 链式调用
  step1()
      .then((result1) => step2(result1))
      .then((result2) => step3(result2))
      .then((finalResult) {
        print("最终结果: $finalResult");
      })
      .catchError((error) {
        print("出错: $error");
      })
      .whenComplete(() {
        print("所有步骤完成");
      });
}

错误处理链

void errorHandlingChain() {
  Future<String> riskyStep1() async {
    await Future.delayed(Duration(seconds: 1));
    throw Exception("步骤1失败");
  }

  Future<String> step2() async {
    await Future.delayed(Duration(seconds: 1));
    return "步骤2";
  }

  riskyStep1()
      .then((result) => step2())  // 不会执行
      .then((result) => print("成功: $result"))
      .catchError((error) {
        print("捕获错误: $error");
        return "默认值";  // 可以恢复
      })
      .then((result) {
        print("恢复后: $result");  // 默认值
      });
}

条件分支

void conditionalChaining() {
  Future<bool> checkPermission(String user) async {
    await Future.delayed(Duration(milliseconds: 500));
    return user == "admin";
  }

  Future<String> fetchData() async {
    await Future.delayed(Duration(seconds: 1));
    return "敏感数据";
  }

  Future<String> fetchPublicData() async {
    await Future.delayed(Duration(milliseconds: 500));
    return "公开数据";
  }

  checkPermission("guest")
      .then((hasPermission) {
        if (hasPermission) {
          return fetchData();
        } else {
          return fetchPublicData();
        }
      })
      .then((data) {
        print("获取到: $data");
      });
}

复杂的链式操作

class OrderProcessor {
  Future<int> createOrder(String userId) async {
    await Future.delayed(Duration(seconds: 1));
    return 1001;  // 订单号
  }

  Future<bool> checkInventory(int orderId, List<String> items) async {
    await Future.delayed(Duration(seconds: 1));
    return items.length < 5;  // 简单逻辑
  }

  Future<double> calculatePrice(int orderId) async {
    await Future.delayed(Duration(seconds: 1));
    return 299.0;
  }

  Future<bool> processPayment(int orderId, double amount) async {
    await Future.delayed(Duration(seconds: 2));
    return true;  // 支付成功
  }

  Future<void> sendNotification(int orderId) async {
    await Future.delayed(Duration(milliseconds: 500));
    print("订单 $orderId 通知已发送");
  }

  Future<void> processOrder(String userId, List<String> items) {
    return createOrder(userId)
        .then((orderId) {
          print("订单创建: $orderId");
          return checkInventory(orderId, items).then((inStock) {
            if (!inStock) throw Exception("库存不足");
            return orderId;
          });
        })
        .then((orderId) {
          return calculatePrice(orderId).then((price) {
            print("订单金额: $price");
            return processPayment(orderId, price).then((paid) {
              if (!paid) throw Exception("支付失败");
              return orderId;
            });
          });
        })
        .then((orderId) => sendNotification(orderId))
        .then((_) => print("订单处理完成"))
        .catchError((e) {
          print("订单处理失败: $e");
        });
  }
}

Future链 vs async/await

// 链式调用风格
Future<String> getUserDataChain(String id) {
  return fetchUser(id)
      .then((user) => fetchUserPosts(user))
      .then((posts) => formatPosts(posts))
      .catchError((e) => "获取数据失败: $e");
}

// async/await风格(更清晰)
Future<String> getUserDataAsync(String id) async {
  try {
    var user = await fetchUser(id);
    var posts = await fetchUserPosts(user);
    return await formatPosts(posts);
  } catch (e) {
    return "获取数据失败: $e";
  }
}

34. Future的async和await

async/await是Dart中处理异步代码的语法糖,让异步代码看起来像同步代码。

基本语法

// 定义异步函数
Future<String> fetchData() async {
  // await 等待Future完成
  var result = await Future.delayed(
    Duration(seconds: 1),
    () => "数据",
  );
  return result;  // 自动包装成Future
}

// 调用
void main() async {
  print("开始获取数据");
  var data = await fetchData();
  print("获取到: $data");
}

// 错误处理
Future<void> processWithError() async {
  try {
    var data = await riskyOperation();
    print("成功: $data");
  } catch (e) {
    print("失败: $e");
  } finally {
    print("清理资源");
  }
}

多个await

Future<void> fetchUserData() async {
  print("开始获取用户数据");

  // 顺序执行(总耗时2秒)
  var user = await fetchUser();        // 1秒
  var posts = await fetchPosts(user);  // 1秒

  print("用户: $user");
  print("帖子数: ${posts.length}");
}

Future<void> fetchParallel() async {
  print("开始并行获取");

  // 并行执行(总耗时1秒)
  var userFuture = fetchUser();        // 1秒
  var postsFuture = fetchAllPosts();   // 1秒

  // 等待两个Future完成
  var user = await userFuture;
  var posts = await postsFuture;

  print("用户: $user");
  print("帖子数: ${posts.length}");
}

实际应用示例

class ApiClient {
  Future<Map<String, dynamic>> get(String url) async {
    await Future.delayed(Duration(seconds: 1));
    return {'url': url, 'data': '模拟数据'};
  }
}

class UserRepository {
  final ApiClient api = ApiClient();

  // 获取用户信息
  Future<Map<String, dynamic>> getUser(int id) async {
    try {
      var response = await api.get('/users/$id');
      return response;
    } catch (e) {
      throw Exception("获取用户失败: $e");
    }
  }

  // 获取用户的完整资料(包含帖子、关注者等)
  Future<Map<String, dynamic>> getUserProfile(int id) async {
    try {
      // 并行获取多个数据
      var userFuture = getUser(id);
      var postsFuture = api.get('/users/$id/posts');
      var followersFuture = api.get('/users/$id/followers');

      // 等待所有请求完成
      var results = await Future.wait([
        userFuture,
        postsFuture,
        followersFuture,
      ]);

      return {
        'user': results[0],
        'posts': results[1]['data'],
        'followers': results[2]['data'],
      };
    } catch (e) {
      throw Exception("获取用户资料失败: $e");
    }
  }
}

// 使用示例
void main() async {
  var repo = UserRepository();

  try {
    var profile = await repo.getUserProfile(123);
    print("用户资料: $profile");
  } catch (e) {
    print("错误: $e");
  }
}

循环中的异步

// 顺序执行(慢)
Future<void> processSequential(List<int> ids) async {
  for (var id in ids) {
    var data = await fetchDataById(id);
    print("处理ID $id: $data");
  }
}

// 并行执行(快)
Future<void> processParallel(List<int> ids) async {
  var futures = ids.map((id) => fetchDataById(id));
  var results = await Future.wait(futures);

  for (var i = 0; i < ids.length; i++) {
    print("处理ID ${ids[i]}: ${results[i]}");
  }
}

// 控制并发数量
Future<void> processBatched(List<int> ids, int batchSize) async {
  for (var i = 0; i < ids.length; i += batchSize) {
    var batch = ids.skip(i).take(batchSize);
    var futures = batch.map((id) => fetchDataById(id));
    var results = await Future.wait(futures);

    for (var j = 0; j < batch.length; j++) {
      print("处理ID ${batch.elementAt(j)}: ${results[j]}");
    }
  }
}

异步生成器(Stream)

// 异步生成器返回Stream
Stream<int> countStream(int max) async* {
  for (int i = 1; i <= max; i++) {
    await Future.delayed(Duration(seconds: 1));
    yield i;  // 发射值
  }
}

// 使用Stream
Future<void> useStream() async {
  var stream = countStream(5);

  // 方式1:await for
  await for (var value in stream) {
    print("收到: $value");
  }

  // 方式2:监听
  stream.listen(
    (value) => print("值: $value"),
    onError: (e) => print("错误: $e"),
    onDone: () => print("完成"),
  );
}