ZetCode

Dart Null 值

最后修改日期:2025 年 6 月 4 日

在 Dart 中,null 表示没有值。它是一个特殊值,表示一个变量尚未被赋予任何对象引用。

随着 Dart 2.12 中引入的空安全,变量默认不能包含 null。要允许 null 值,我们必须显式地将它们声明为可空类型。

基本 Null 概念

Dart 的类型系统区分可空类型和非可空类型。? 后缀表示可空类型。! 运算符断言一个值是非 null 的。

空感知运算符有助于安全地处理潜在的 null 值。这些包括 ??, ?., 和 ??=。它们提供了处理 null 情况的简洁方式。

理解 null 对于编写健壮的 Dart 代码至关重要。正确的 null 处理可以防止运行时 null 引用异常,并使代码更具可预测性。

可空类型 vs 非可空类型

Dart 2.12+ 默认强制执行空安全。变量不能为 null,除非使用 ? 类型后缀显式声明为可空。

main.dart
void main() {
  // Non-nullable variable
  String name = 'Alice';
  // name = null; // Compile-time error
  
  // Nullable variable
  String? nullableName = 'Bob';
  nullableName = null; // Allowed
  
  print('Name: $name');
  print('Nullable name: $nullableName');
}

第一个变量不能为 null,而第二个变量可以。尝试将 null 赋值给非可空变量会导致编译时错误。

$ dart main.dart
Name: Alice
Nullable name: null

Null 断言运算符

! 运算符断言一个表达式是非 null 的。当您确定可空变量包含非 null 值时,请使用它。

main.dart
void main() {
  String? maybeName = 'Alice';
  
  // Without assertion
  print('Length: ${maybeName?.length}');
  
  // With assertion
  print('Length: ${maybeName!.length}');
  
  maybeName = null;
  // print('Length: ${maybeName!.length}'); // Runtime error
}

第一个 print 使用安全导航 (?.)。第二个使用 ! 断言非 null。被注释掉的行如果取消注释,将引发运行时异常。

$ dart main.dart
Length: 5
Length: 5

空感知运算符

Dart 提供了几个运算符来进行简洁的 null 处理。?? 运算符在遇到 null 时提供一个默认值。

main.dart
void main() {
  String? name;
  
  // Null coalescing operator
  String displayName = name ?? 'Guest';
  print('Welcome, $displayName!');
  
  // Null-aware assignment
  name ??= 'Anonymous';
  print('Hello, $name!');
  
  // Null-aware access
  print('Name length: ${name?.length}');
}

当 name 为 null 时,?? 运算符提供 'Guest'。??= 运算符仅在变量为 null 时才赋值。?. 运算符安全地访问属性。

$ dart main.dart
Welcome, Guest!
Hello, Anonymous!
Name length: 9

集合中的空安全

Dart 中的集合可以包含 null 值,除非显式限制。我们可以指定列表元素或映射值是否可以为 null。

main.dart
void main() {
  // List with nullable elements
  List<int?> nullableNumbers = [1, null, 3];
  print('Nullable numbers: $nullableNumbers');
  
  // Map with nullable values
  Map<String, String?> userData = {
    'name': 'Alice',
    'email': null
  };
  print('User data: $userData');
  
  // Non-nullable list
  List<int> numbers = [1, 2, 3];
  // numbers.add(null); // Error
}

第一个列表和映射允许 null 值。最后一个列表禁止 null。类型系统在编译时强制执行这些约束。

$ dart main.dart
Nullable numbers: [1, null, 3]
User data: {name: Alice, email: null}

可选参数和 Null

Dart 函数可以具有默认为 null 的可选参数。命名参数默认为可选,而位置参数需要 []。

main.dart
void greet(String name, [String? title]) {
  print('Hello ${title != null ? '$title ' : ''}$name');
}

void printUser({String name = 'Guest', int? age}) {
  print('Name: $name, Age: ${age ?? 'unknown'}');
}

void main() {
  greet('Alice'); // No title
  greet('Bob', 'Dr.'); // With title
  
  printUser(); // Default name
  printUser(name: 'Charlie', age: 30); // All parameters
}

greet 函数有一个可选的位置参数。printUser 使用带有默认值的命名参数。两者都展示了 null 处理模式。

$ dart main.dart
Hello Alice
Hello Dr. Bob
Name: Guest, Age: unknown
Name: Charlie, Age: 30

最佳实践

来源

Dart 空安全文档

本教程通过实际示例涵盖了 Dart 的 null 值,展示了空安全特性和模式。

作者

我的名字是 Jan Bodnar,我是一名充满激情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在教授编程方面拥有超过十年的经验。

列出 所有 Dart 教程