求可演示Dart中value type与reference type差异的示例代码
Dart 类型核心概念与可运行示例
三个核心概念的直白定义
- 值类型(value type):赋值、函数传参时直接拷贝完整数据的类型,对副本做任何修改都不会影响原始变量。
- 引用类型(reference type):赋值、函数传参时只拷贝对象的内存地址(引用)的类型,如果对象本身是可变的,通过副本修改对象内部状态时,所有指向这个对象的变量都会感知到变化。
- 规范化(canonicalized):编译器或运行时做的内存优化,内容完全相同的常量实例会被全局复用,不会重复创建新对象,这个特性和类型是值还是引用没有必然关联。
关于int类型的归属结论
Dart 语法层面没有独立的值类型分支,所有用户可直接操作的对象都是引用类型,int也不例外。
很多人误以为int是值类型,本质是因为int是不可变对象——你根本没有办法修改一个int实例本身的内容,所有看起来像“修改int”的操作,本质都是让变量指向新的int实例,再加上小范围整数做了默认规范化,最终表现和值类型完全一致,日常开发中完全可以按值类型的直觉用。
可运行示例代码
示例1:int的行为表现
void main() { int a = 10; int b = a; // 这里不是修改原10这个对象,而是让b指向新的20实例 b = 20; print(a); // 输出10,原变量不受任何影响 print(b); // 输出20 }
示例2:典型可变引用类型的行为
和上面int的表现做对比就能看出差异:
// 自定义可变类 class MutableCounter { int count; MutableCounter(this.count); } void main() { var counterA = MutableCounter(10); var counterB = counterA; // 拷贝引用,两个变量指向同一个实例 // 直接修改实例内部的可变属性 counterB.count = 20; print(counterA.count); // 输出20,原变量指向的对象被改动 print(counterB.count); // 输出20 }
示例3:规范化(canonicalized)的实际表现
class ConstPoint { final int x, y; // const构造函数创建的是可被规范化的常量对象 const ConstPoint(this.x, this.y); } void main() { // 小整数默认做了规范化,相同值指向同一个实例 int num1 = 10; int num2 = 10; print(identical(num1, num2)); // 输出true // 超出默认优化范围的大整数不会自动规范化,相同值可能是不同实例 int bigNum1 = 1 << 63; int bigNum2 = 1 << 63; print(identical(bigNum1, bigNum2)); // 原生VM下输出false,web平台可能有差异 // const创建的自定义常量,只要构造参数完全相同,就会被规范化复用 var point1 = const ConstPoint(1, 2); var point2 = const ConstPoint(1, 2); print(identical(point1, point2)); // 输出true // 非const创建的普通对象,哪怕内容完全相同,也不会自动规范化 var point3 = ConstPoint(1, 2); var point4 = ConstPoint(1, 2); print(identical(point3, point4)); // 输出false }
关键结论总结
- 不要拿其他语言(比如C#、Java)的类型分类硬套Dart,Dart里所有可操作对象都是引用语义。
- int、bool、String、double这些基础类型用起来和值类型没区别,核心原因是它们都是不可变对象,不存在“通过引用别名修改原对象”的可能性。
- 规范化只是内存优化手段,不管什么类型,只要是const常量、符合运行时优化规则,都可能被规范化,不能用这个特性判断类型是值还是引用。
内容的提问来源于stack exchange,提问作者森口万太郎
相关产品推荐
相关产品推荐

