Dart的const理解

在Flutter的Widget.build()函数里,const使用频率非常的高,但一直没有真正的理解其作用,从而也导致不知道何时应该使用const。

只有真正做到“知其然知其所以然”,才能真正的写出高质量高性能的程序。

A const variable is a compile-time constant. (Const variables are implicitly final.)

两个关键点:

  1. 初始化时机:编译时
  2. 可变性:完全不可变

常量变量

1
2
3
4
5
6
7
// 全局常量变量
const a = '123';

// 类级常量变量
class Demo {
static const b = '456';
}

常量变量又可以称为编译时变量,其值要求是编译时常数

什么是编译时常数?编译时就要能确定下来,如数值、字符串、常量集合、常量实例等。

1
2
3
4
const a = 123; // 数值
const a = '123'; // 字符串
const a = const [1, 2, 3] // 常量集合
const a = Constobj(); // 常量实例

常量这个概率在很多的语言里都有,Java里的常量定义为public static final来定义,数值型和字符型的常量好理解,与其他语言的常量类似,但有所差异的是常量集合常量实例

常量集合 与 final变量的区别

主要区别在于:常量集合是完全不可变,不仅仅只是变量不能再次赋值,包括对象的属性也不能修改

1
2
3
4
5
6
7
8
9
// final 变量
final a = [1, 2, 3];
a[0] = 5; // 可修改对象的属性

// const常量
const b = [1,2,3];
b[0] = 5; // 报错
var c = const [1, 2, 3];
c[0] = 3; // 报错

常量实例

创建常量实例的要求:

  1. const 修饰 构造函数
  2. 所有的成员变量都必须是final
  3. 实例化时,使用常量构造函数,且使用const修饰
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Point {
final int x;
final int y;
final int z=11;
static int m = 12; // 静态变量不需要是final
const Point(this.x, this.y);
}
void main() {
const p1 = Point(1, 2); // 常量实例
final p2 = const Point(1, 2); // 常量实例

var p3 = Point(1,2);// 普通实例
print(p1 == p2); // 结果为true
print(p1 == p3); // 结果为false
}

常量实例的特点:

  1. 对应类:需要是Immutable类(不可变类)
  2. 对象的特点:编译时可完全确定,构造参数相同的常量实例复用

作用

  1. 通过复用,减少内存占用
  2. 通过减少垃圾回收次数,提升性能

使用场景
Flutter里的Widget的build()方法执行次数非常多,为了减少每次重绘时的内存占用和垃圾回收次数,大量使用了const

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);

// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}

Android里类似的实现: 对象垃圾池,如Message

感谢您的阅读,本文由 刘阳 版权所有。如若转载,请注明出处:刘阳(https://handsomeliuyang.github.io/2022/05/28/%E6%97%A5%E5%B8%B8%E5%AD%A6%E4%B9%A0-Dart%E7%9A%84const%E7%90%86%E8%A7%A3/
Anki助手:解决孩子复习和家长辅导的痛点
从开发者角度思考单元测试的价值