当前位置: 首页 > news >正文

深入理解 Dart 中的 const 与 final:编译时常量与运行时常量

在 Dart 的开发中,我们频繁地使用 const 和 final 来声明变量。表面上看,它们都用于创建“不可变”的变量,但背后的机制却有着本质的区别。这种区别直接影响着程序的性能和内存分配。本文将深入探讨这两者的不同,并阐明其各自的适用场景。

一、核心定义与哲学
final:运行时常量

概念:一个 final 变量只能被赋值一次。这个赋值操作发生在运行时。

哲学:它关心的是值的不可变性,而不关心这个值具体是什么,只要在运行时能确定下来即可。

const:编译时常量

概念:一个 const 变量是编译时常量。它的值必须在代码编译阶段(即程序运行前)就是完全明确、确定的。

哲学:它既是值的不可变,也是值的“编译期可知”。这允许 Dart 编译器进行深度优化。

二、关键差异与技术细节
理解它们区别的最佳方式是通过对比。

特性 final const
赋值时机 运行时(如:在函数内部、类实例初始化时) 编译时(代码在运行前就必须确定)
初始化的值 可以是运行时才能计算出的值(如:DateTime.now()) 必须是编译时常量(如:字面量、其他const变量、常量表达式)
与类的关系 可以是实例变量,每个对象可以拥有不同的 final 值。 不能是实例变量,只能是 static const 类变量。
对象创建 使用 new 或 const 构造。 必须使用 const 构造。
代码示例分析:

dart
// --- final 示例 ---
final currentTime = DateTime.now(); // 正确:运行时获取值
final list = []; // 正确:在运行时创建了一个空列表
list.add(1); // 正确:虽然 list 是 final,但其内容是可变的(除非是 const List)

class Example {
final int id;
Example(this.id); // 正确:id 在对象构造时(运行时)被初始化
}

// --- const 示例 ---
const pi = 3.14159; // 正确:字面量是编译时常量
const double doublePi = pi * 2; // 正确:pi 是 const,表达式是常量表达式

// const currentTime = DateTime.now(); // 错误!DateTime.now() 不是编译时常量

const list = [1, 2, 3]; // 正确:创建了一个编译时常量列表
// list.add(4); // 错误:const List 是不可变的

class ConstExample {
static const defaultId = 0; // 正确:静态常量
// const int id; // 错误:实例变量不能是 const
}
最重要的区别:const 构造函数

当与类一起使用时,const 的关键作用体现在构造函数上。

dart
class Point {
final int x;
final int y;
const Point(this.x, this.y);
}

void main() {
// 两个不同的对象,在内存中占用两个不同的空间
final p1 = Point(1, 2);
final p2 = Point(1, 2);
print(identical(p1, p2)); // false

// 使用 const 构造函数创建编译时常量
// 编译器会进行优化,相同的常量在内存中只存在一份
const p3 = Point(1, 2);
const p4 = Point(1, 2);
print(identical(p3, p4)); // true! p3 和 p4 是同一个对象
}
在上面的例子中,identical(p3, p4) 返回 true,这证明了 Dart 编译器对 const 构造的对象进行了规范化(canonicalization),所有相同的 const 对象在内存中共享同一个实例。这对于不变的对象(如配置、标志位、坐标等)能有效节省内存。

三、如何选择:实践指南
使用 final:

当你需要一个变量在运行时初始化且之后不可变时。

用于类的实例变量。

当变量的值来自于外部输入、计算或异步操作时。

使用 const:

当你需要一个编译期就能确定的常量值时。

用于定义字面量常量集合(如 const [‘a', ‘b']),以确保集合本身也是不可变的。

用于创建不可变的、共享的类实例(通过 const 构造函数),以提升性能。

四、总结
final 保证了引用不变,而 const 则保证了值本身在编译时就是唯一且不变的。理解并正确使用 const 是编写高性能、内存友好的 Dart/Flutter 应用的关键一步。在 Flutter 的 Widget 树中,大量使用 const 构造函数可以显著减少不必要的 Widget 重建,从而提升渲染性能。

http://www.jsqmd.com/news/48745/

相关文章:

  • python: 缩放图片
  • java和python做出什么
  • java和linux
  • 湖南工程学院 学科实践与创新协会电气部 幕后揭示
  • KEYDIY PAK06-ZB Phone As Key: Replace Your Car Key with Your Smartphone for European/American Cars
  • 湖南工程学院 学科实践与创新协会电气部 新生选拔赛
  • It Calculus
  • 20232412 2024-2025-1 《网络与系统攻防技术》实验六实验报告
  • 20232309 2025-2026-1 《网络与系统攻防技术》实验六实验报告
  • 2025 ICPC 西安区域赛 VP
  • K8s学习笔记(二十二) 网络组件 Flannel与Calico - 详解
  • 完整教程:人脸识别4-Windows下基于MSVC编译SeetaFace6
  • CF1483D-Useful Edges
  • Paddle-CLS图像分类_环境安装
  • 2025年11月短视频运营公司最新TOP5推荐:业绩增长与效率筛选标准
  • 实用指南:【10】MFC入门到精通——MFC 创建向导对话框、属性页类、属性表类、代码
  • 2025-09-10-Wed-T-Kubernetes
  • 一文入门 Dify平台的插件开发
  • 20232326 2025-2026-1 《网络与系统攻防技术》实验六实验报告
  • 2025年11月小程序开发公司TOP5评测:功能落地与适配筛选标准,西南地区企业选择指南
  • 2025年11月云南数字人供应商最新TOP5推荐:精细建模优质选择
  • 第二讲下梯度下降算法
  • Java云计算技术怎样应对故障
  • 2025-08-02-Sat-T-RabbitMQ
  • Nand2Tetris 笔记
  • 审美积累暗色UI设计超越美学的用户体验
  • 具有超高峰值抑制比和低功耗的全光可调谐微波滤波器
  • 11.23
  • 实用指南:F-INR: Functional Tensor Decomposition for Implicit Neural Representations
  • 实验3 类和对象_基础编程 - yuyue