一、集合比较
在 Dart
中,DeepCollectionEquality
类是 collection
包中的一个类,用于比较两个集合(如 List
、Set
、Map
等)是否相等,并且进行深度比较。这意味着它不会比较集合的引用,而是会递归地比较集合中的每个元素的内容,确保集合内部的内容也完全相同。
通常,==
运算符只能比较对象的引用是否相等,而 DeepCollectionEquality
会比较集合中每个元素的值。
依赖包:
collection: ^1.18.0
import 'package:collection/collection.dart';
void main() {
// 创建两个相同的嵌套列表
var list1 = [
{'name': 'Alice', 'age': 30},
{'name': 'Bob', 'age': 25},
];
var list2 = [
{'name': 'Alice', 'age': 30},
{'name': 'Bob', 'age': 25},
];
// 使用 DeepCollectionEquality 进行深度比较
var equality = DeepCollectionEquality();
print(equality.equals(list1, list2)); // 输出: true
}
实际开发中的代码:
import 'package:collection/collection.dart';
bool _compare(dynamic a, dynamic b) {
if (a is String || a is int || a is double || a is bool) {
return a == b;
} else if (a is Set || a is Map || a is List || a is Iterable) {
return const DeepCollectionEquality().equals(a, b);
}
return a == b;
}
二、用==
比较对象类型
上面提到了话题是比较两个集合是否完全一样,比较的是两个集合中的所有属性,包含元素的顺序;
但有时候我们也希望通过==
符号就能简单的对边两个对象是否相等,就像比较两个数字或字符串一样;
假设我们有一个类:
class Person {
final String id;
final String name;
Person({required this.id, required this.name});
}
我们需要简单的通过==
来判断两个Person类对象是否相等,默认情况下,比较的是引用地址:
/// p1、p2引用地址不一样,所以不相同
Person p1 = Person(id: 1, name: '张三');
Person p2 = Person(id: 1, name: '张三');
Person p3 = p1;
print(p1 == p2); // 输出 false
print(p1 == p3); // 引用地址相同,输出 true
既然默认情况下,比较的是引用地址,而不是比较具体属性,那我们需要重写类的==
符号,来改变这一规则,修改后的Person
class Person {
final int id;
final String name;
Person({required this.id, required this.name});
@override
bool operator ==(covariant Object other) {
/// identical(this, other) 用于判断两个对象的引用地址是否相同——默认情况
/// runtimeType == other.runtimeType 用于判断两个对象的类型是否相同
/// 最后,比较类的各个属性是否相等
/// 所以:只要是引用相等,或者,属于同一种类,并且各个属性相等,那么两个都想就相等;
return identical(this, other) ||
other is Person &&
runtimeType == other.runtimeType &&
id == other.id &&
name == other.name;
}
}
Person
改成如上结构后:
前面的p1和p2相等了。
既然p1和p2相等了,那么包含p1的集合是否contains了p2呢?答案是否定了,接着往下看。
var set = {p1};
print(set.contains(p2)); // 期望 true,但实际是 false
思考:是不是以为set.contains(p2)
返回true
呢?实际上返回的还是false
,为什么呢?
实际原因是:
- 集合类型(如 Set、Map 的 key)在判断元素是否相等时,既会用 ==,也会用 hashCode。
- 只有当两个对象的 hashCode 相等时,才会进一步用 == 判断是否“真正相等”。
- 如果你只重写了 ==,但没有重写 hashCode,那么即使两个对象“看起来相等”,它们的 hashCode 可能不同,导致集合类无法正确识别它们为同一个元素。
所以需要重写hashCode:
@override
int get hashCode => id.hashCode;
最后的Person
类:
class Person {
final int id;
final String name;
Person({required this.id, required this.name});
@override
bool operator ==(covariant Object other) {
/// identical(this, other) 用于判断两个对象的引用地址是否相同——默认情况
/// runtimeType == other.runtimeType 用于判断两个对象的类型是否相同
/// 最后,比较类的各个属性是否相等
/// 所以:只要是引用相等,或者,属于同一种类,并且各个属性相等,那么两个都想就相等;
return identical(this, other) ||
other is Person &&
runtimeType == other.runtimeType &&
id == other.id &&
name == other.name;
}
@override
int get hashCode => id.hashCode;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。