final
一、简述
final 是 Dart 语言 60 个关键字其中之一。它用于修饰声明的对象,例如:
final String name = 'keywords - final';
final List<int> ages = [10, 20, 30];
final Person person = Person(name:'关键字');
... // 穷举省略
二、特点
-
必须进行初始化
final 变量声明时必须进行初始化赋值,而且只能在声明时或构造函数中进行初始化。 -
只能赋值一次
一旦 final 变量被初始化后,其值就不能再更改。 -
值可以是常量或表达式
final 变量的值可以是编译时常量、字面量、其他final变量或由常量表达式计算得出的结果。 -
可以是顶级变量或局部变量
final 关键字可用于顶级变量(全局范围内)或局部变量(函数、方法范围内)。
三、优点
-
不可变性
final 属性一旦被赋予初始值后,其值无法再被修改。这种不可变性确保了属性的值在对象生命周期内的稳定性,避免了意外的修改或错误。 -
安全性
由于 final 属性的值是不可变的,它们在多线程环境下是线程安全的。不需要额外的同步机制来保护 final 属性的访问和修改,从而降低了并发编程的复杂性。 -
可预测性
final 属性的值在对象创建时确定,并且不能再改变。这使得代码的行为更加可预测,避免了由于属性值的变化导致的不确定性。 -
性能优化
在编译时,对于使用 final 修饰的属性,编译器可以进行更多的优化。由于这些属性的值是不可变的,编译器可以进行常量折叠、内联优化等,提高程序的执行效率。 -
代码简洁性
使用 final 关键字可以使代码更加简洁清晰,明确地指示属性的不可变性。这有助于提高代码的可读性和维护性,减少意外的错误和bug。
四、应用时机
在 Dart 中,final 关键字可以用于以下几种情况的应用时机:
-
常量值
当你需要声明一个不可变的常量值时,可以使用final关键字。这些常量值在程序执行期间是不会改变的,并且在编译时可以进行优化。例如,声明一个永远不会改变的数学常量PI
可以使用final double PI = 3.14159;
。 -
构造函数参数
通过在构造函数的参数前面加上 final 关键字,可以将它们作为不可变的实例属性。这样,在对象创建后,这些属性的值将保持不变。这种用法常见于需要在对象创建时传递不可变数据的情况。例如:class Person { const Person(this.name); final String name; }
-
局部变量
当你有一个在其生命周期内不会改变的局部变量时,可以使用 final 关键字进行声明。这样可以提醒开发人员该变量不会被修改,并且可能触发一些编译时的优化。例如,在一个循环中,使用 final 关键字声明的局部变量可以避免重复计算,提高性能。
需要注意的是,虽然 final 关键字意味着不可变性,但并不表示它是唯一的选择。另外一个类似的关键字是 const,它用于声明编译时常量。
五、应用实例
下面是 final 的一些使用实例以及验证一些问题,如下:
-
基础使用
// 修饰常量 final double PI = 3.1415926; // 修饰表达式 final int age = 10 + 12; // 修饰类属性 class Person { const Person({this.name}); final String name; } // 修饰类 final Person person = Person(name:'keyword - final'); ...
-
赋值后不可更改
void main() { final String name = 'keyword - final'; // bad code name = 'keyword - const'; }
上述代码语法提示
Error: The final variable 'name' can only be set once.
上述代码运行报错提示Error: Can't assign to the final variable 'name'.
。 -
修饰对象不可变,但对象内的可变属性是可变的
class Animal { Animal(this.name, this.age); final String name; int age; @override String toString() => 'Animal\n name:$name;age:$age'; } final Animal dog = Animal('狗', 1); dog.age = 2; print(dog.toString()); // Animal-name:狗;age:2
-
修饰的容器类对象,该对象不可变,但是容器内的元素可增加和减少以及改变
// good code - List final List<int> ages = [10, 20, 30]; ages.add(40); ages.removeAt(0); ages[2] = 110; print(ages); // [20, 30, 110] // bad code // Error: The final variable 'ages' can only be set once. ages = []; // 或者字典集合 // good code - Map final Map<String, dynamic> map = {}; map.putIfAbsent('key', () => 1); print(map); // bad code // Error: The final variable 'ages' can only be set once. map = {};
六、总结
上面是我对 final 的一些认识,其实 final 的知识与应用还有很多其他的妙用,需要我们一起探索和发现以及使用它。来吧! 欢迎你加入探究者的行列,去领略这门语言的奇特之处。