Menu
CoddyTech

final 与 const 字段

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

在类中声明字段时,你可以使用 final 或 const 来控制初始化后值是否可以更改。两者都会创建不可变的值,但它们的工作方式不同。

final 字段只能设置一次,但它的值是在运行时确定的。你可以在声明时为它赋值,也可以通过构造函数赋值:

class Person {
  final String name;
  final DateTime createdAt = DateTime.now();
  
  Person(this.name);
}

Person p = Person('Alice');
// p.name = 'Bob';  // 错误:不能重新给 final 字段赋值

创建对象时会设置 name,而 createdAt 会记录当前时间。初始化后,这两个值都会锁定。

static const 字段的值必须在编译时已知。它属于类本身,并由所有实例共享:

class Circle {
  static const double pi = 3.14159;
  final double radius;
  
  Circle(this.radius);
  
  double get area => Circle.pi * radius * radius;
}

关键区别:final 字段可以保存运行时计算出的值(例如 DateTime.now()),而 const 要求值在编译时确定。实例字段不能直接声明为 const,类级别只允许使用 static const。

challenge icon

挑战

简单

让我们构建一个产品目录系统,展示 final 和 static const 字段之间的区别。你将创建具有不可变属性和共享配置值的产品。

你将把代码整理到两个文件中:

  • product.dart:定义一个表示商店商品的 Product 类。这个类应包含:
    • 一个设为 0.08 的 static const double taxRate(所有产品共用的 8% 税率)
    • 一个设为 'USD' 的 static const String currency
    • 一个用于保存产品名称的 final String name(通过构造函数设置)
    • 一个用于保存产品基础价格的 final double basePrice(通过构造函数设置)
    • 一个 final String sku(库存单位),它将前缀与产品名称组合起来,并在初始化列表中计算,方式为先写 'SKU-',再接上大写形式的名称
    • 一个接收 name 和 basePrice 的构造函数
    • 一个用于计算含税价格的 getter priceWithTax
    • 一个用于打印产品信息的 display() 方法
  • main.dart:导入产品类并创建两个产品:
    • 一个基础价格为 999.99 的 'Laptop'
    • 一个基础价格为 29.99 的 'Mouse'
    按照上面列出的顺序,对每个产品调用 display()。

display() 方法应按以下确切格式打印:

[sku] - [name]: [basePrice] [currency] (with tax: [priceWithTax] [currency])

显示时,使用 toStringAsFixed(2) 将 priceWithTax 四舍五入到小数点后 2 位。

预期输出:

SKU-LAPTOP - Laptop: 999.99 USD (with tax: 1079.99 USD)
SKU-MOUSE - Mouse: 29.99 USD (with tax: 32.39 USD)

亲手试试

import 'product.dart';

void main() {
  // TODO: 创建一个名为 'Laptop' 的 Product,基础价格为 999.99
  
  // TODO: 创建一个名为 'Mouse' 的 Product,基础价格为 29.99
  
  // TODO: 依次对每个产品调用 display()(先 Laptop,后 Mouse)
  
}
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: Dart 在线编译器