1.2. Dart 语言基础

Dart 是 Flutter 的开发语言,由 Google 设计,兼具 JIT(开发期快速迭代)和 AOT(发布期高性能编译)能力。

1.2.1. 变量与类型

1.2.1.1. 类型声明

// 显式类型
String name = 'Dart';
int age = 10;

// 类型推断(var)
var message = 'Hello';        // 推断为 String
var count = 42;               // 推断为 int

// 动态类型(dynamic)
dynamic value = 'Hello';
value = 123;                  // 可重新赋值为其他类型

// 常量
final String appName = 'MyApp';     // 运行时赋值一次
const double pi = 3.14159;           // 编译时常量

小技巧

  • final:值在运行期确定,赋值后不可变

  • const:值在编译期已知,且不可变

  • const 对象称为编译时常量,Dart 会将其规范化

1.2.1.2. 内置类型

// 数字
int i = 42;
double d = 3.14;
num n = 42;        // int 和 double 的父类型

// 字符串
String s1 = '单引号';
String s2 = "双引号";
String s3 = '''多行
字符串''';
String msg = 'Hello, $s1!';           // 插值
String calc = '2 + 3 = ${2 + 3}';     // 表达式插值

// 布尔
bool isDone = true;
bool isActive = false;

// 列表(数组)
List<int> numbers = [1, 2, 3];
var fruits = ['apple', 'banana'];
fruits.add('orange');
print(fruits[0]);          // apple

// 集合
Set<int> unique = {1, 2, 3, 3};    // {1, 2, 3}

// 映射
Map<String, int> scores = {
  'Alice': 95,
  'Bob': 87,
};
scores['Charlie'] = 92;

1.2.2. 空安全(Null Safety)

Dart 全面支持空安全,类型默认不可为 null:

String name = 'Alice';
// name = null;       // 编译错误!

String? nullable = null;    // 可空类型,使用 ?
nullable = 'Bob';

// 安全访问操作符
print(nullable?.length);    // null 安全访问

// 空值合并操作符
String display = nullable ?? '默认值';

// 断言非空(谨慎使用)
String definitely = nullable!;

警告

使用 ! 断言非空前,确保变量确实不为 null,否则运行时会抛出异常。

1.2.3. 函数

1.2.3.1. 基本用法

// 标准函数
int add(int a, int b) {
  return a + b;
}

// 箭头函数(单表达式)
int square(int x) => x * x;

// 可选命名参数
void greet({required String name, int age = 18}) {
  print('Hello, $name ($age)');
}
greet(name: 'Alice', age: 30);
greet(name: 'Bob');             // age 使用默认值

// 可选位置参数
String join(String a, [String? b, String? c]) {
  return '$a${b ?? ''}${c ?? ''}';
}
join('a');          // 'a'
join('a', 'b');     // 'ab'

1.2.3.2. 函数是一等公民

// 函数赋值给变量
var fn = (int x) => x * 2;
print(fn(5));       // 10

// 高阶函数
void execute(int x, int Function(int) op) {
  print(op(x));
}
execute(5, (x) => x * x);   // 25

// 匿名函数
[1, 2, 3].map((e) => e * 2).toList();   // [2, 4, 6]

1.2.4. 类与对象

class Person {
  final String name;    // 不可变属性
  int age;

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

  // 命名构造函数
  Person.guest() : this('Guest', 0);

  // 命名构造函数 + 初始化列表
  Person.fromJson(Map<String, dynamic> json)
      : name = json['name'] as String,
        age = json['age'] as int;

  // 方法
  void introduce() {
    print('Hi, I\'m $name, $age years old.');
  }

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

  // setter
  set birthday(int year) {
    age = DateTime.now().year - year;
  }
}

// 使用
final alice = Person('Alice', 30);
alice.introduce();
print(alice.isAdult);     // true

1.2.4.1. 继承与混入

class Animal {
  void sound() => print('...');
}

// 继承
class Dog extends Animal {
  @override
  void sound() => print('Woof!');
}

// 混入(Mixin)
mixin Flyable {
  void fly() => print('Flying!');
}

mixin Swimmable {
  void swim() => print('Swimming!');
}

// 使用混入(可以多个)
class Duck extends Animal with Flyable, Swimmable {
  @override
  void sound() => print('Quack!');
}

小技巧

混入(Mixin)是 Dart 代码复用的重要方式,比多重继承更灵活安全。

1.2.4.2. 抽象类与接口

// 抽象类
abstract class Shape {
  double get area;      // 抽象 getter
  void draw();          // 抽象方法
}

// 实现(所有类都隐式定义了接口)
class Circle implements Shape {
  final double radius;
  Circle(this.radius);

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

  @override
  void draw() => print('Drawing Circle');
}

1.2.5. 异步编程

1.2.5.1. Future

// 异步函数返回 Future
Future<String> fetchData() async {
  await Future.delayed(Duration(seconds: 1));
  return '数据加载完成';
}

// 使用 async/await
void load() async {
  print('加载中...');
  String data = await fetchData();
  print(data);
}

// Future 链式调用
fetchData()
  .then((data) => print(data))
  .catchError((error) => print('出错: $error'))
  .whenComplete(() => print('完成'));

1.2.5.2. Stream

// 创建 Stream
Stream<int> countStream(int max) async* {
  for (int i = 1; i <= max; i++) {
    await Future.delayed(Duration(seconds: 1));
    yield i;           // 产出值
  }
}

// 消费 Stream
void listen() async {
  await for (final value in countStream(3)) {
    print(value);     // 每秒输出 1, 2, 3
  }
}

备注

async* 和 yield 用于生成 Stream,await for 用于消费 Stream。