一、起因
在Flutter开发中,官方的Widget使用了使用大量的const修饰符的构造函数,这样做的好处,在于重复使用Widget,不用频繁的构建与销毁Widget。
在Flutter中,会频繁的调用build()方法,每次调用后Flutter会构建新的Widget子树,销毁子树上所有Widget。
对于不用重新构建的Widget,我们可以使用const作为修饰符,构建Widget的 常量实例,就可以重复使用,不至于每次都销毁后,重新构建,消耗性能。这里有个概念常量实例,在下面会详细说到。
二、const与final
在dart中声明常量有两种const、final,两者的区别
-
const编译时常量只能在编译的时候确定常量值,只能赋值一次,只能赋值常量值。
-
final运行时常量可以在运行时赋值,只能赋值一次,可以赋值任意类型。
| 声明常量方式 | 何时赋值 | 赋值类型 | 赋值次数 |
|---|---|---|---|
const | 编译时 | 常量值 | 一次 |
final | 编译时、运行时 | 任意类型 | 一次 |
三、const使用方式
-
作为关键字,用于声明常量
const name = '小明'; const levels = [1, 2, 3]; -
作为修饰符,用于创建常量值
/// 虽然只赋值一次,但可以修改里面的内容 final levels = [1, 2, 3]; levels[0] = 10; /// 使用常量修饰符,就不能修改里面的内容 final levels = const [1, 2, 3]; levels[0] = 10; //报错:Unsupported operation: Cannot modify unmodifiable list /// 看了以上的示例,你可能感觉是脱裤子放屁,多此一举。 /// 这是只是展示一下修饰符的作用,真正的使用场景是:创建常量实例,重复使用常量实例,提高性能。
四、常量值
1、普通常量值
- 基本常量
- 数值型
- 字符串型
- 包含数值与字符串的表达式
- 集合常量
- 包含基本常量类型的List、Map、Set、Records
示例:
const name = '小明'; // 字符串型
const english = 86.0; // 数值型
const math = 100; // 数字型号
const desc = '$name 总分:${english + math}'; // 表达式
const person = (name: name, desc: desc); // Records常量
const scores = [english, math]; // List<num>常量
2、 常量实例
在我们认知中,一个类的实例对象的构建,是在运行过程中,通过构造函数构建的。而使用const修饰的构造函数,并使用const修饰构建的实例对象,该实例对象就称为常量实例,能够在编译时,作为常量值使用。
如何创建常量实例
-
新建可以构建常量实例的类
使用
const修饰类的构造函数,该类可以构建普通的实例(运行时的类实例),也可以构建常量实例(编译时常量)。 -
将该类构建为常量实例
- 使用final赋值常量时,需要再次使用
const修饰,才能真正的作为常量实例使用。 - 使用const赋值常量时,不需要使用
const修饰。
- 使用final赋值常量时,需要再次使用
示例:
/// 新建一个可构建常量实例的类
class Person {
final String name;
final int age;
const Person({required this.name, required this.age});
}
/// const赋值常量,将该类构建为常量实例
const person1 = Person(name:'xiaoming', age: 18);
/// final赋值常量,需要const修饰,才能将该类构建为常量实例
const person2 = const Person(name:'xiaoming', age: 18);
举例验证
const constPerson = Person(name: 'xiaoming', age: 18); //常量实例
final finalPerson = Person(name: 'xiaoming', age: 18); //普通实例
final fianlConstPerson = const Person(name: 'xiaoming', age: 18); //常量实例
/// const_person 与 final_person 不是一个对象的引用
print(identical(constPerson, finalPerson)); // false
/// const_person 与 fianl_const_person 是一个对象的引用,此为常量实例
print(identical(constPerson, fianlConstPerson)); // true
/// 再构建一个普通的实例,判断是否与之前的普通实例同属于一个对象
final finalPerson1 = Person(name: 'xiaoming', age: 18); // 普通实例
print(identical(finalPerson, finalPerson1)); // false
上面的示例,直观的展现了:
- 构建的多个常量实例,都是引用同一个地址,也就是同属于一个对象。
- 构建的普通实例,不是同属一个对象。
bool identical(Object? a, Object? b)用于判断2个对象,是否同属于一个对象。