关于不变形一直是热定话题,尤其是在前段。像Immutable.js这样的库和单向数据流等其他概念都认为,当数据不可变时,更容易管理数据。
在面向对象和函数是编程中,一个不可变的对象是指,一旦对象创建之后状态是不能修改的。想对应的是可变对象,创建之后,对象状态是可以修改的。
好了,那Dart是怎样做的呢?我们有几个概念很适合内置的不变性和不可变对象,从const修饰符和const构造函数开始。 不要与ES6中的const混淆,后者只是一个不可变的绑定。
// 定义USER为常量,初始化。const USER = { name: 'Joe'; }// 这样将抛出异常.USER = {};// 但是这样不会;以为是绑定的不可变,可以修改对象USER.name = 'Jill';复制代码
在Dart中,const是一个不可变绑定,也是不可变对象。
main() { const user = const { 'name': 'Joe'}; // 抛出 Static error: "Constant variables cannot be assigned a value". user = {}; // 抛出 Runtime error: "Unsupported operation: Cannot modify unmodifiable Map". user['name'] = 'Jill';}复制代码
所有类型,例如(Null, String, int, double, num, bool, Map, List, Symbol),都可以是不可变的,而且可以给自定类型添加const构造函数。
class User { final String name; const User(this.name);}main() { const user = const User('Joe');}复制代码
让我们回顾一下 - const实例既是不可变的绑定,又在语言层面强制执行,既是根本不可变的 - 也是在编译时就确定的 - 也就是说,任何两个实例都被认为是等价的,并且在运行时只能由单个实例表示。 例如,以下内容相当简单,它只在运行时分配一个实例:
class User { final String name; final Listcars; User(this.name, { this.cars});}main() {// 虽然循环100次,但是只有一个对象 for (var i = 0; i < 100; i++) { const users = const { 'Matan': const User( 'Matan Lurey', cars: const [ 'Truck', 'Jeep', 'GoKart', ], ), }; }}复制代码
更多关于const和final请参考Dart官方文档
通过package:meta静态分析检查
当然,const是有限制的 - 必须在编译时创建类对象。所以不能完成如下,在运行时,从数据库读出数据,创建对象。我们现在介绍package:meta的immutable
注解。
import 'pacakge:meta/meta.dart';// 因为当前类使用@immutable注解,所以变量必须是final的@immutableclass User { final String name; User(this.name)}复制代码
你可以使用这个注解帮助开发者,强制类是不可变的。但是不像const那么规范,但是他依然对开发者有用。