@override
bool equals(Object? e1, Object? e2) {
if (e1 is Set) {
return e2 is Set && SetEquality(this).equals(e1, e2);
}
if (e1 is Map) {
return e2 is Map && MapEquality(keys: this, values: this).equals(e1, e2);
}
if (!_unordered) {
if (e1 is List) {
return e2 is List && ListEquality(this).equals(e1, e2);
}
if (e1 is Iterable) {
return e2 is Iterable && IterableEquality(this).equals(e1, e2);
}
} else if (e1 is Iterable) {
if (e1 is List != e2 is List) return false;
return e2 is Iterable && UnorderedIterableEquality(this).equals(e1, e2);
} else if (e1 is (Object?, Object?)) { // new
return e2 is (Object?, Object?) && // new
PairEquality(this, this).equals(e1, e2); // new
}
return _base.equals(e1, e2);
}
@override
int hash(Object? o) {
if (o is Set) return SetEquality(this).hash(o);
if (o is Map) return MapEquality(keys: this, values: this).hash(o);
if (!_unordered) {
if (o is List) return ListEquality(this).hash(o);
if (o is Iterable) return IterableEquality(this).hash(o);
} else if (o is Iterable) {
return UnorderedIterableEquality(this).hash(o);
} else if (o is (Object?, Object?) { // new
return PairEquality(this, this).hash(o); // new
}
return _base.hash(o);
}
import "package:collection/collection.dart";
/// Builds a recursive equality.
///
/// Allows for easily creating equalities for structures,
/// like collections or similar, that refer back to the deep equality
/// for element equality.
class DeepEquality implements Equality<Object?> {
List<Equality<Object?>> _equalities = const [];
/// Creates recursive equality.
///
/// Each function in [factories] is called with this deep equality
/// as argument, and should return an equality for a specific type.
///
/// When comparing or hashing, each of these equalities are tried,
/// in original iteration order, until one's [Equality.isValidKey]
/// returns true, then that equality is used on the objects.
///
/// For [equals], both arguments must be valid.
///
/// If no factory-created equality matches, the [base] equality
/// is used instead. It *must* accept all remaining values.
DeepEquality(Iterable<Equality<Object?> Function(Equality<Object?>)> factories,
[Equality<Object?> base = const DefaultEquality()]) {
_equalities = [for (var factory in factories) factory(this), base];
}
@override
bool equals(Object? a, Object? b) {
if (identical(a, b)) return true;
for (var equality in _equalities) {
if (equality.isValidKey(a) && equality.isValidKey(b)) {
return equality.equals(a, b);
}
}
return false;
}
@override
int hash(Object? a) {
for (var equality in _equalities) {
if (equality.isValidKey(a)) {
return equality.hash(a);
}
}
return a.hashCode;
}
@override
bool isValidKey(Object? o) => true;
}
/// Creates an [Equality] from equals and hash code functions.
class PredicateEquality<A> implements Equality<A> {
final bool Function(A, A) _equals;
final int Function(A) _hash;
final bool Function(Object?)? _isValid;
PredicateEquality({
required bool Function(A, A) equals,
required int Function(A) hash,
bool Function(Object?)? isValidKey,
}) : _equals = equals,
_hash = hash,
_isValid = isValidKey;
@override
bool equals(A a, A b) => _equals(a, b);
@override
int hash(A a) => _hash(a);
@override
bool isValidKey(Object? o) => _isValid?.call(o) ?? o is A;
}
// Usage:
void main() {
var deepListEq = DeepEquality([
ListEquality.new,
], const DefaultEquality());
print(deepListEq.equals([1, [2, 3]], [1, [2, 3]]));
var deepPairListEq = DeepEquality([
ListEquality<Object?>.new,
(eq) => PredicateEquality<(Object?, Object?)>(
equals: ((Object?, Object?) pair1, (Object?, Object?) pair2) =>
eq.equals(pair1.$1, pair2.$1) && eq.equals(pair1.$2, pair2.$2),
hash: ((Object?, Object?) pair) =>
Object.hash(eq.hash(pair.$1), eq.hash(pair.$2)),
)
]);
var v1 = ([1, (1, 2)], [(1, [2])]);
var v2 = ([1, (1, 2)], [(1, [2])]);
print(deepPairListEq.equals(v1, v2));
}
2条答案
按热度按时间5hcedyr01#
所谓“深度相等”,你的意思是传递遍历集合,这些集合在Dart中不是自然相等的,然后使用其他一些“ListEquality”函数来完成这些集合的相等。
没有简单的办法。原因是您不能抽象超过记录类型。如果你想在记录上定义一个相等,它在具有相同形状的记录的字段上使用
==
以外的东西,你需要为每个记录形状定义一个 *。我可以给予你一对
字符串
即使这样也对您的示例没有帮助,在您有单例记录的情况下,您还需要一个类来处理它。
我假设你的配对不仅在顶部,因为这样你就可以这样做:
型
因此,您可能需要 * 重写 *
DeepCollectionEquality
来识别您知道如何比较的记录类型(它不是为了注入更多可识别的类型而编写的)。型
你需要为你需要识别的每一个记录形状添加新的案例。
(That建议也许
DeepCollectionEquality
应该用一些“识别类型并为其提供相等性”对象进行参数化。但现在,它不是)。这种可配置的深度相等的可能实现可以是如下内容:
型
3mpgtkmj2#
The spec说:
记录具有值相等性,这意味着如果两个记录具有相同的形状并且对应的字段相等,则它们相等。
关于记录是否具有原始相等性,甚至同一性,还有很多内容,但您必须阅读规范。我不打算在这里剪切和粘贴它。
我的解释是,简单地使用==就可以满足几乎所有需要“深度”相等的情况。