为什么要用 equatable
在 dart 中如果要判断一个对象的是否相等需要复写 operator ==
和 hashCode
。总是这样的代码很无趣也没有效率。比如 要判断 两个 Person 对象是否相等,需要这样写
class Person { const Person(this.name); final String name; @override bool operator ==(Object other) => identical(this, other) || other is Person && runtimeType == other.runtimeType && name == other.name; @override int get hashCode => name.hashCode; } 复制代码
identical(this, other)
判断这两个对象是否为同一个,如果同一个,那当然相等了。
other is Person && runtimeType == other.runtimeType && name == other.name; 复制代码
这三个必须同时成立才能判断相等。
- 确保是 person 对象
- 即便是 person 对象,但可能是 person 的某个子类,所以还得进一步判断 runtimeType
- 最后还得判断所有属性相等。
还好我们有 equatable 帮我完成 operator ==
和 hashCode
复写的工作。只需要我们给出需要判断的属性即可。
使用 equatable
第一步先安装
flutter pub add equatable 复制代码
然后引用
import 'package:equatable/equatable.dart'; 复制代码
使用的时候可以直接继承,也可以用 mixin 的方式
class Person extends Equatable { const Person(this.name, this.favorite); final String name; final List<String> favorite; @override List<Object?> get props => [name, favorite]; } 复制代码
或
class Person with EquatableMixin { const Person(this.name, this.favorite); final String name; final List<String> favorite; @override List<Object?> get props => [name, favorite]; } 复制代码
注意事项
参与检测的属性都必须是 final
如果参与检测的属性是可变的,那么 计算出的 hascode 也是可以变的,再用 hascode 判断相等就不可靠了。有的时候 final 也防止不了改变,这个时候就靠自己避免了。
比如 在 Person 类中 favorite 是一个 list,虽然 list 本身不能修改,但是 list 的内容是可以修改的。
可以把 favorite 私有化,避免外部修改,这样只要保证 person 内部不修改 favorite 就可以了。
class Person with EquatableMixin { const Person(this.name, List<String> favorite):_favorite=favorite; final String name; final List<String> _favorite; @override List<Object?> get props => [name, _favorite]; } 复制代码
判断相等,不需要判断参数为 null
因为 null 除了和自己相等,不和任何其它变量相等。判断 null 显得多此一举。
如果自己 重载 operator ==, 不要这样写
class Person { final String name; // ··· bool operator ==(Object? other) => other != null && other is Person && name == other.name; } 复制代码
要这样写
class Person { final String name; // ··· bool operator ==(Object other) => other is Person && name == other.name; } 复制代码
toString
最后还有一个小福利。equatable 还 override toString 方法,通过 override stringify 来控制如何显示 toString 的内容。
@override bool? get stringify => true; 复制代码
stringify 是 equatable 属性,默认是 null,如果我们修改为 true,在调用 toString 的时候,会显示包含 props 的更详细的信息。