Menu
CoddyTech

? 和 ! 运算符

本课属于 Coddy Dart 学习旅程的“面向对象编程”单元。第 25 课,共 110 课。

处理可空类型时,Dart 提供了两个重要的运算符,帮助你安全地访问值。空安全访问运算符 ?. 和 空断言运算符 ! 让你可以控制如何处理可能为 null 的值。

?. 运算符可以安全地访问可空值的属性或方法。如果值为 null,整个表达式会返回 null,而不会导致程序崩溃:

String? name = 'Alice';
print(name?.length);  // 5

name = null;
print(name?.length);  // null(不会崩溃!)

! 运算符告诉 Dart:“我确定这个值不是 null。”它会将可空类型转换为不可空类型,但如果这个值实际上是 null,就会抛出错误:

String? maybeName = 'Bob';
String definite = maybeName!;  // 没问题,我们断言它不是 null
print(definite.length);  // 3

String? empty = null;
// String crash = empty!;  // 运行时错误!值为 null

如果你想妥善处理 null 值,请使用 ?.。只有在你绝对确定某个值存在时才使用 !,例如,在用 if 语句检查后,或者你知道逻辑可以保证该值存在。过度使用 ! 会违背空安全的目的,还可能导致运行时崩溃。

challenge icon

挑战

简单

让我们构建一个商品库存系统,演示如何使用 ?. 和 ! 运算符安全地处理可空值。

你将创建两个文件来组织代码:

  • product.dart:定义一个表示库存商品的 Product 类。有些商品的信息完整,有些商品仍在编目。你的类应包含:
    • 不可为空的 String name,每件商品都必须有名称
    • 不可为空的 double price,每件商品都必须有价格
    • 可为空的 String? description,有些商品还没有描述
    • 可为空的 String? category,有些商品还没有分类
    • 一个构造函数,将 name 和 price 作为必需参数
    • 一个 getDescriptionLength() 方法,使用 ?. 返回描述的长度;如果没有描述,则返回 null
    • 一个 getCategoryUppercase() 方法,使用 ! 返回大写的类别。此方法假定类别已经设置
    • 一个 displayProduct() 方法,用于打印商品信息;当描述为 null 时显示 No description,当类别为 null 时显示 Uncategorized
  • main.dart:导入你的商品类,并演示这两个运算符:
    • 创建一件名为 'Laptop'、价格为 999.99 的商品,然后将其描述设为 'High-performance computing device',类别设为 'Electronics'
    • 创建一件名为 'Mystery Item'、价格为 49.99 的商品(将描述和类别留为 null)
    • 对于 Laptop:调用 displayProduct(),使用 getDescriptionLength() 打印 Description length: [length],并使用 getCategoryUppercase() 打印 Category: [uppercase]
    • 对于 Mystery Item:调用 displayProduct(),并使用 getDescriptionLength() 打印 Description length: [length](这将显示 null)

displayProduct() 方法应按以下格式打印:

Product: [name] - $[price]
Description: [description or "No description"]
Category: [category or "Uncategorized"]

预期输出:

Product: Laptop - $999.99
Description: High-performance computing device
Category: Electronics
Description length: 32
Category: ELECTRONICS
Product: Mystery Item - $49.99
Description: No description
Category: Uncategorized
Description length: null

亲手试试

import 'product.dart';

void main() {
  // TODO: 创建一个名为 'Laptop'、价格为 999.99 的产品
  // 然后将它的描述设置为 'High-performance computing device'
  // 并将它的类别设置为 'Electronics'
  
  // TODO: 创建一个名为 'Mystery Item'、价格为 49.99 的产品
  // 让描述和类别保持为 null
  
  // TODO: 对于 Laptop:
  // - 调用 displayProduct()
  // - 使用 getDescriptionLength() 打印 "Description length: [length]"
  // - 使用 getCategoryUppercase() 打印 "Category: [uppercase]"
  
  // TODO: 对于 Mystery Item:
  // - 调用 displayProduct()
  // - 使用 getDescriptionLength() 打印 "Description length: [length]"
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Dart 在线编译器