当前位置: 首页 > 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.gsyq.cn/news/58547.html

相关文章:

  • python: 缩放图片
  • 湖南工程学院 学科实践与创新协会电气部 幕后揭示
  • 20232309 2025-2026-1 《网络与系统攻防技术》实验六实验报告
  • 20232326 2025-2026-1 《网络与系统攻防技术》实验六实验报告
  • 2025年11月云南数字人供应商最新TOP5推荐:精细建模优质选择
  • 2025-08-02-Sat-T-RabbitMQ
  • Nand2Tetris 笔记
  • 审美积累暗色UI设计超越美学的用户体验
  • 实用指南:F-INR: Functional Tensor Decomposition for Implicit Neural Representations
  • 实验3 类和对象_基础编程 - yuyue
  • java中sql注入的防范措施是什么
  • 【第五章:计算机视觉-项目实战之推荐/广告体系】2.粗排算法-(4)粗排算法模型多目标算法(Multi Task Learning)及目标融合
  • Java基础(代码块,内部类,函数式编程,常用API,GUI编程)
  • 代码源2025长训_noip
  • Day46(16)-F:\硕士阶段\Java\课程代码\后端\web-ai-code\web-ai-project02\tlias-web-management
  • 完整教程:日本生活-东京新干线乘车经验-流程介绍
  • 代码随想录算法训练营第三天:链表part01
  • 第二讲类神经网络训练不起来
  • 一些唐话
  • 2025-05-29-Thu-T-设计模式
  • 2024-11-26-Tue-T-SSM
  • 20232424 2025-2026-1 《网络与系统攻防技术》实验六实验报告
  • 11-25
  • 2023-09-19-E-文章管理
  • P14457 [ICPC 2025 Xian R] Killing Bits
  • P13536 [IOI 2025] 神话三峰(triples)(Part 1)
  • 深入解析:HiTooler File Finder: macOS上速度碾压Spotlight,媲美「Everything」的文件搜索神器
  • 29232428 2025-2026-1 《网络与系统攻防技术》实验六
  • 【做题记录】HZOJ 多校-数论/多校-字符串/多校-图论Ⅲ
  • 2025-11-23