Dart 编程简介
Flutter - Dart 编程入门 (包含空安全 Null Safety)
Section titled “Flutter - Dart 编程入门 (包含空安全 Null Safety)”Flutter 应用使用 Dart 编程语言编写。Dart 是一种由 Google 开发的现代、面向对象、客户端优化的语言。它专为在任何平台(移动、Web、桌面、服务器)上构建快速应用而设计。理解 Dart 基础知识对于 Flutter 开发至关重要。
本章涵盖与 Flutter 相关的基本 Dart 概念,包括 Null Safety(空安全),这是一项重要的特性,旨在帮助防止 null 引用错误。
Dart 基本程序结构
Section titled “Dart 基本程序结构”每个 Dart 应用都必须有一个顶级的 main() 函数,它作为程序的入口点。
// 这是单行注释。
/* 这是 多行注释。*/
// 应用的主要入口点。void main() { // print() 用于在控制台输出。 print('Hello, Dart!');}变量和数据类型
Section titled “变量和数据类型”变量存储对值的引用。Dart 是类型安全的(type-safe),这意味着变量类型在编译时(如果使用 dynamic 则在运行时)进行检查。
-
类型注解(Type Annotation): 明确声明类型:
-
var: Dart 根据初始值推断类型。一旦推断,类型就不能改变。 -
dynamic: 允许变量类型在运行时更改。谨慎使用,因为它牺牲了类型安全。
空安全 (Null Safety)
Section titled “空安全 (Null Safety)”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)
Section titled “常量 (final 和 const)”-
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]); // 通过索引访问:Ananames.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/elsefor循环 (包括for-in)while和do-while循环break和continueswitch/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'); // 断言:分数必须是正数}面向对象编程 (OOP)
Section titled “面向对象编程 (OOP)”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...}异步编程 (async, await, Future)
Section titled “异步编程 (async, await, Future)”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/awaitFuture<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。