Skip to content

Dart 编程简介

Flutter - Dart 编程入门 (包含空安全 Null Safety)

Section titled “Flutter - Dart 编程入门 (包含空安全 Null Safety)”

Flutter 应用使用 Dart 编程语言编写。Dart 是一种由 Google 开发的现代、面向对象、客户端优化的语言。它专为在任何平台(移动、Web、桌面、服务器)上构建快速应用而设计。理解 Dart 基础知识对于 Flutter 开发至关重要。

本章涵盖与 Flutter 相关的基本 Dart 概念,包括 Null Safety(空安全),这是一项重要的特性,旨在帮助防止 null 引用错误。

每个 Dart 应用都必须有一个顶级的 main() 函数,它作为程序的入口点。

// 这是单行注释。
/*
这是
多行注释。
*/
// 应用的主要入口点。
void main() {
// print() 用于在控制台输出。
print('Hello, Dart!');
}

变量存储对值的引用。Dart 是类型安全的(type-safe),这意味着变量类型在编译时(如果使用 dynamic 则在运行时)进行检查。

  • 类型注解(Type Annotation): 明确声明类型:

  • var: Dart 根据初始值推断类型。一旦推断,类型就不能改变。

  • dynamic: 允许变量类型在运行时更改。谨慎使用,因为它牺牲了类型安全。

Dart 的健全空安全(sound null safety)意味着变量不能持有 null,除非你明确允许它们持有。这显著减少了运行时 null 错误。

  • 非空(默认): 变量在使用前必须初始化,并且不能赋值为 null。

  • 可空 (?): 在类型后添加 ? 表示变量可以是 null。

  • 空感知运算符(Null-aware Operators):

    • ?. (条件访问 Conditional Access):仅当对象非空时才访问属性/方法,否则返回 null。message?.length
    • ?? (If Null 运算符):如果左侧表达式为 null,则提供一个默认值。String name = nullableName ?? 'Guest';
    • ??= (空感知赋值 Null-aware Assignment):仅当变量当前为 null 时才赋值。count ??= 0;
  • 断言运算符 (!): 使用 ! 告诉 Dart 你确定表达式在运行时不会是 null。谨慎使用;如果它是 null,会抛出异常。

  • int len = nullableString!.length; // 如果 nullableString 是 null,则抛出异常

  • late 关键字: 用于声明在声明后初始化的非空变量。对于 Flutter 中在 initState 中初始化的实例变量非常有用。

  • late String description;

    • 如果在初始化之前访问,会抛出错误。
    • 可以与 final 结合使用:late final String apiData;
  • final: 变量只能设置一次。其值在运行时确定。

  • const: 将变量标记为编译时常量。值必须在编译时已知。const 对象是深度不可变的且规范化的(只创建一个实例并重复使用)。

  • 数字(Numbers): int (任意大小的整数), double (64位浮点数)。两者都是 num 的子类型。
  • 字符串(Strings): UTF-16 码单元序列。使用单引号 ('...') 或双引号 ("...")。支持字符串插值 ($ 或 ${expression})。
  • 布尔值(Booleans): bool 类型,值为 true 和 false。
  • 列表(Lists,Arrays): 有序的对象集合。List<int> numbers = [1, 2, 3];
  • 集合(Sets): 无序的唯一项集合。Set<String> fruits = {'apple', 'banana', 'apple'}; // {'apple', 'banana'}
  • 映射(Maps,Dictionaries): 键值对集合。键必须唯一。Map<String, int> scores = {'Alice': 90, 'Bob': 85};
  • Runes: 表示 Unicode 码点。
  • Symbols: 用于反射的不透明标识符(在 Flutter 应用中较少见)。
String s1 = 'Single quotes work.'; // 单引号可用。
String s2 = "Double quotes also work."; // 双引号也可用。
String s3 = 'It\'s easy to escape.'; // 转义很简单。
int value = 10;
String interpolated = 'The value is $value.'; // 值为 10。
String calculated = 'Value times two is ${value * 2}.'; // 值乘以二为 20。
List<String> names = ['Ana', 'Bob', 'Charlie'];
print(names[0]); // 通过索引访问:Ana
names.add('David');
Map<String, String> capitals = {
'USA': 'Washington D.C.',
'UK': 'London'
};
print(capitals['UK']); // 通过键访问:London

函数在 Dart 中是第一类对象(可以赋值给变量,作为参数传递)。

// 带类型注解的基本函数
int add(int a, int b) {
return a + b;
}
// 单表达式函数的简写语法
double multiply(double x, double y) => x * y;
// 函数可以有可选参数
// 位置可选参数(使用 [])
String say(String from, String msg, [String? device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
// 调用示例:say('Bob', 'Hi') 或 say('Bob', 'Hi', 'smartphone')
// 命名可选参数(使用 {})
void enableFlags({bool? bold, bool? hidden}) {
print('Bold: ${bold ?? false}, Hidden: ${hidden ?? false}');
}
// 调用示例:enableFlags(bold: true) 或 enableFlags(hidden: false, bold: true)
// 命名必需参数(使用 'required' 关键字)
void printUser({required String name, int? age}) {
print('User: $name, Age: ${age ?? 'Unknown'}');
}
// 调用示例:printUser(name: 'Alice') 或 printUser(name: 'Bob', age: 30)
void main() {
print(add(5, 3)); // 8
print(multiply(4.0, 2.5)); // 10.0
print(say('Alice', 'Hello')); // Alice says Hello
enableFlags(hidden: true);
// 匿名函数(闭包)
var numbers = [1, 2, 3];
numbers.forEach((number) {
print('Number: $number');
});
}

Dart 支持标准的控制流:

  • if/else
  • for 循环 (包括 for-in)
  • while 和 do-while 循环
  • break 和 continue
  • switch/case (Dart 的 switch 功能强大,支持任意对象,并且需要 break 或其他退出语句)
  • assert (在开发阶段使用,如果布尔条件为 false 则中断执行。在生产代码中被禁用。)
void processScore(int score) {
if (score >= 90) {
print('Grade A'); // 成绩 A
} else if (score >= 80) {
print('Grade B'); // 成绩 B
} else {
print('Grade C or lower'); // 成绩 C 或更低
}
var list = [10, 20, 30];
for (var item in list) {
print(item);
}
for (int i = 0; i < 3; i++) {
print('Index $i'); // 索引 $i
}
// Assert 示例 (仅在 debug 模式下工作)
// assert(score > 0, 'Score must be positive'); // 断言:分数必须是正数
}

Dart 是一种面向对象的语言,具有类和基于 Mixin 的继承。

  • 类(Classes): 对象的蓝图。使用 class 关键字。
  • 构造函数(Constructors): 用于创建类的实例(对象)的特殊函数。可以是无名构造函数、命名构造函数 (ClassName.namedConstructor()) 或工厂构造函数 (factory ClassName(...))。
  • 字段(Fields,Instance Variables): 类内部的变量。
  • 方法(Methods): 类内部的函数。
  • 继承(Inheritance): 使用 extends 继承另一个类。重写超类成员时使用 @override 注解。
  • Mixins: 一种在多个类层次结构中复用代码的方式,无需深层继承。使用 mixin 关键字定义,使用 with 应用。
  • 接口(Interfaces): Dart 没有特定的 interface 关键字。每个类都隐式定义一个接口。使用 implements 来保证一个类提供了接口的成员。
class Vehicle {
String model;
int year;
// 构造函数(赋值字段的简写)
Vehicle(this.model, this.year);
void honk() {
print('Beep beep!'); // 哔哔!
}
@override
String toString() => '$year $model'; // 返回年份和型号的字符串表示
}
class Car extends Vehicle {
int numberOfDoors;
// 调用超类构造函数
Car(String model, int year, this.numberOfDoors) : super(model, year);
// 重写方法
@override
void honk() {
print('Honk honk!'); // 嘀嘀!
super.honk(); // 可选地调用超类方法
}
}
// Mixin 示例
mixin Electric {
void charge() {
print('Charging...'); // 充电中...!
}
}
// 使用 Mixin 的类
class ElectricCar extends Car with Electric {
ElectricCar(String model, int year) : super(model, year, 4);
}
void main() {
var myCar = Car('Toyota Camry', 2022, 4);
print(myCar); // 2022 Toyota Camry
myCar.honk(); // Honk honk! Beep beep!
var myElectricCar = ElectricCar('Tesla Model 3', 2023);
myElectricCar.charge(); // Charging...
}

Dart 使用 Future 对象表示将来可用的值,并使用 async/await 关键字编写看起来同步的异步代码。

  • Future<T>: 表示一个潜在的类型为 T 的值或错误,将在稍后完成。
  • async: 将函数标记为异步函数;允许在其中使用 await。async 函数会自动将其返回值包装在 Future 中。
  • await: 暂停执行,直到它等待的 Future 完成。只能在 async 函数内部使用。
// 模拟获取数据的函数(返回一个 Future)
Future<String> fetchData() {
// 模拟网络延迟
return Future.delayed(const Duration(seconds: 2), () => 'Data Fetched!'); // 数据已获取!
}
// 使用 async/await
Future<void> printData() async {
print('Fetching data...'); // 正在获取数据...
try {
String data = await fetchData(); // 等待 Future 完成
print(data);
} catch (e) {
print('Error fetching data: $e'); // 获取数据出错:$e
}
}
// 使用 .then() 进行回调(替代方法)
void printDataWithThen() {
print('Fetching data (using .then)...'); // 正在获取数据(使用 .then)...
fetchData().then((data) {
print(data);
}).catchError((error) {
print('Error fetching data: $error'); // 获取数据出错:$error
});
}
void main() async { // main 函数可以是异步的
await printData();
print('Finished.'); // 已完成。
// printDataWithThen(); // 如果不 await,这将并发运行
}

这涵盖了 Flutter 所需的 Dart 基础知识。随着你的进步,你将会遇到更高级的特性,如 Streams、Isolates 和 Generators。