【Flutter for OpenHarmony--Dart 入门日记】第2篇:常量声明详解——`const` 与 `final` 到底有什么区别?
本文深入解析了 Dart 中 const 和 final 的区别与应用场景。const 用于编译时确定的常量,如数学常数 π,具有内存优化优势;而 final 适用于运行时确定的只读变量,如时间戳或用户输入。两者核心区别在于初始化时机:const 在编译期固定,final 在运行时首次赋值后锁定。文章通过代码示例展示了常见用法,并指出典型误区,如 const 不能包含变量。最后给出了实践建议:静态
【Dart 入门日记】第2篇:常量声明详解——const 与 final 到底有什么区别?
作者:灰灰勇闯IT
时间:2026年1月
系列定位:零基础记录 Dart 学习过程,适合编程新手、Flutter 初学者
本文重点:深入理解const(编译时常量)与final(运行时常量)的使用场景与本质区别
目录
- 1. 为什么需要常量?
- 2.
const:编译期就确定的“绝对不变”值 - 3.
final:运行时才确定的“一次赋值”变量 - 4. 核心对比:
constvsfinal—— 编译时 vs 运行时 - 5. 深入理解:为什么 Dart 要区分这两种常量?
- 6. 实战建议:什么时候用
const,什么时候用final? - 7. 常见误区与调试技巧
- 8. 小结 & 下期预告
1. 为什么需要常量?
在编程中,有些值从诞生起就不该被修改。比如:
- 数学常数:π(3.14159…)、e(2.718…)
- 配置项:API 地址、版本号
- 时间戳:用户点击按钮的精确时刻
如果这些值被意外修改,程序逻辑就会出错。因此,Dart 提供了两种“不可变”机制:const 和 final。
🌟 我的思考:
昨天学了var,今天学“不能变的变量”,感觉像是在给数据上锁——有的锁在写代码时就焊死了(const),有的锁在程序跑起来那一刻才扣上(final)。
2. const:编译期就确定的“绝对不变”值
2.1 场景引入:圆周率 π 不可更改
计算圆的周长公式是:C = 2 × π × r。
其中,π 是一个数学常数,永远不变。这种值就应该用 const 声明。
2.2 const 基本语法与代码示例
语法:
const 常量名 = 值;
示例:计算半径为 5 的圆的周长
void main() {
const pi = 3.1415926; // 编译时常量
var radius = 5.0;
var circumference = 2 * pi * radius;
print('半径为 $radius 的圆,周长是 $circumference');
}
输出:
半径为 5.0 的圆,周长是 31.415926
](https://i-blog.csdnimg.cn/direct/932ad3c1d3ac4d22b724ccacb0101011.png#pic_center)](https://i-blog.csdnimg.cn/direct/3a140aa5698049bda640a3ffd3288734.png#pic_center)
✅ 特点:
- 值在编译时就必须确定
- 所有
const对象在内存中是单例(相同值只存一份) - 可用于注解、元数据等需要编译期常量的场景
2.3 ❌ 常见错误:const 表达式中不能包含变量
const 的值必须是“字面量”或由其他 const 组成的表达式,不能依赖运行时才能知道的变量。
错误示例:
void main() {
var radius = 5.0;
// ❌ 错误!radius 是变量,无法在编译时确定
const area = 3.1415926 * radius * radius;
}
报错信息类似:
Error: Constant expressions can't refer to non-constant variables.
](https://i-blog.csdnimg.cn/direct/2344a96146ab4fdbb514d84dd8824ab8.png#pic_center)
💡 正确做法:改用
final,或者把整个表达式移到运行时计算。
3. final:运行时才确定的“一次赋值”变量
3.1 场景引入:获取当前时间作为唯一操作时间戳
假设我们要记录用户点击按钮的精确时间。这个时间只有在程序运行到那一行代码时才能知道,但它一旦获取,就不应再变。
这就是 final 的典型用武之地。
3.2 final 基本语法与代码示例
语法:
final 变量名 = 值;
示例:获取当前年份
import 'dart:core';
void main() {
final now = DateTime.now(); // 运行时获取当前时间
final currentYear = now.year;
print('当前年份是:$currentYear');
}
输出(假设今天是 2026 年):
当前年份是:2026
](https://i-blog.csdnimg.cn/direct/623f25a2821742c1a5ab2c6639278536.png#pic_center)
✅ 特点:
- 值在运行时第一次赋值后锁定
- 可以使用变量、函数返回值等动态内容初始化
- 每次运行程序,
final的值可能不同(如时间、随机数)
4. 核心对比:const vs final —— 编译时 vs 运行时
| 特性 | const |
final |
|---|---|---|
| 初始化时机 | 编译时 | 运行时 |
| 值是否可变 | 绝对不可变 | 初始化后不可变 |
| 能否使用变量初始化 | ❌ 不行 | ✅ 可以 |
| 内存优化 | 相同值共享同一对象(单例) | 每次创建新对象 |
| 适用场景 | 数学常量、配置字面量 | 时间、用户输入、API 返回值 |
代码对比示例:
void main() {
// ✅ const:编译期确定
const pi = 3.1415926;
const appName = "My Flutter App";
// ✅ final:运行期确定
final timestamp = DateTime.now().millisecondsSinceEpoch;
final randomId = DateTime.now().microsecondsSinceEpoch % 1000;
print('App: $appName, π ≈ $pi');
print('时间戳: $timestamp, 随机ID: $randomId');
}
5. 深入理解:为什么 Dart 要区分这两种常量?
这背后是 性能 与 灵活性 的权衡:
-
const用于极致优化
因为值在编译时已知,Dart 可以:- 将相同
const对象合并(节省内存) - 在 AOT 编译(如 Flutter Release 模式)中直接内联值
- 支持用作 Widget 构造函数的
const参数(提升 UI 渲染性能)
- 将相同
-
final保证运行时安全
当值依赖外部输入(如网络、传感器、时间),final确保“只读一次”,防止后续逻辑意外修改。
📌 Flutter 开发提示:
在构建 Widget 时,尽量用const修饰那些不会变的子组件,例如:const Text('欢迎来到我的 App', style: TextStyle(fontSize: 18));这能显著减少重建开销!
6. 实战建议:什么时候用 const,什么时候用 final?
✅ 用 const 当:
- 值是字面量(数字、字符串、布尔值)
- 值由其他
const组合而成 - 用于配置、枚举、UI 静态文本
const double gravity = 9.8;
const List<String> weekdays = ['Mon', 'Tue', 'Wed'];
✅ 用 final 当:
- 值来自函数调用(如
DateTime.now()) - 值来自参数或用户输入
- 值在构造函数中初始化(类成员)
class User {
final String name;
final int loginTime;
User(this.name) : loginTime = DateTime.now().millisecondsSinceEpoch;
}
7. 常见误区与调试技巧
❌ 误区1:“final 和 const 一样,都是常量”
→ 不完全对!final 是运行时常量,const 是编译时常量,性能和使用限制完全不同。
❌ 误区2:“const 可以放在函数里动态计算”
→ 不行!const 必须在编译时就能算出结果。
✅ 调试技巧:
- 在 VS Code 中,悬停
const变量会显示 “compile-time constant” - 尝试给
const赋变量值,编译器会立即报错,这是好事! - 在 Flutter 中,开启 “Performance Overlay” 可观察
constWidget 是否被跳过重建
8. 小结 & 下期预告
✅ 本篇收获:
- 掌握了
const的使用:适用于编译期已知的绝对常量(如 π) - 理解了
final的价值:适用于运行时确定但后续不变的数据(如时间戳) - 明确了二者的核心区别:编译时 vs 运行时
- 避开了“在
const中使用变量”的经典错误
🎯 动手练习:
尝试写一个 Circle 类,用 const 存储 π,用 final 存储半径,并提供计算面积和周长的方法。
➡️ 下期预告:
《【Dart 入门日记】第3篇:Dart 的基础数据类型全解析——int、double、String、bool 与 null 安全》
我们将系统学习每一种内置类型,并揭开 Dart 空安全(Null Safety)的神秘面纱!
💬 互动时间:
你在项目中更常用 const 还是 final?有没有因为混淆两者而踩过坑?欢迎在评论区分享你的故事!如果你觉得这篇文章帮你理清了概念,别忘了 点赞 + 收藏 + 关注,你的支持是我持续更新的最大动力!
📎 附:所有代码均可直接运行
环境要求:Dart SDK 3.0+,推荐使用 VS Code + Dart/Flutter 插件
更多推荐

所有评论(0)