如何比较两个对象以查看它们是否是同一实例

问题描述 投票:0回答:8

假设我有一个具有许多实例变量的类。我想重载 == 运算符(和 hashCode),以便我可以使用实例作为映射中的键。

class Foo {
  int a;
  int b;
  SomeClass c;
  SomeOtherClass d;
  // etc.

  bool operator==(Foo other) {
    // Long calculation involving a, b, c, d etc.
  }
}

比较计算可能会很昂贵,所以我想在进行计算之前检查

other
是否与
this
是同一实例。

如何调用 Object 类提供的 == 运算符来执行此操作?

dart
8个回答
71
投票

您正在寻找“identical”,它将检查两个实例是否相同。

identical(this, other);

更详细的例子?

class Person {
  String ssn;
  String name;

  Person(this.ssn, this.name);

  // Define that two persons are equal if their SSNs are equal
  bool operator ==(Person other) {
    return (other.ssn == ssn);
  }
}

main() {
  var bob = new Person('111', 'Bob');
  var robert = new Person('111', 'Robert');

  print(bob == robert); // true

  print(identical(bob, robert)); // false, because these are two different instances
}

9
投票

您可以使用

identical(this, other)


3
投票

为了完整起见,这是对现有答案的补充答案。

如果某个类

Foo
覆盖==
,那么默认实现是返回它们是否是同一个对象。 
文档指出:

所有对象的默认行为是当且仅当此对象和其他对象是同一对象时返回 true。


3
投票
这就是我比较深度两个对象的方式,它们不一样:

class Foo{ String uid; bool isActiv; Foo(this.uid, this.isActiv){} Map<String, dynamic> toJson() => _$FooToJson(this); } Foo A = Foo("alpha", true); Foo B = Foo("alpha", true); print(A.toJson().toString() == B.toJson().toString()); // true B.uid = "beta"; print(A.toJson().toString() == B.toJson().toString()); // false
    

3
投票
您可以使用

Equatable

class Foo extends EquatableMixin{ int? a; int? b; SomeClass? c; SomeOtherClass? d; Foo(this.a,this.b,this.c,this.d); // this does the job, it overrides the hashcode and equals operator // give all properties to this `props` @override List<Object> get props => [a,b,c,d]; } class SomeOtherClass with EquatableMixin{ String name; SomeOtherClass(this.name); @override List<Object> get props => [name]; } class SomeClass with EquatableMixin{ String name; SomeClass(this.name); @override List<Object> get props => [name]; } Foo foo = Foo(1,2,SomeOtherClass("roger"),SomeOtherClassObject("mack")); Foo foo2 = Foo(1,2,SomeOtherClass("roger"),SomeOtherClassObject("mack")); print(foo == foo2) // prints true
所以,我们不需要手动重写 

==

hashcode()
 方法
图书馆会这么做的。

注意:内部对象(SomeClass 和 SomeOtherClass)也应该使用 EquatableMixin,我们也可以扩展它或用作 mixin


2
投票
当您尝试比较两个传递引用的对象(如类、列表、映射、集合等)时... 您需要将变量设置为 const 变量才能比较它们,因为编译器通过

address 或 hashCode 来比较它们,如下面的代码。

class Foo { final int a; final int b; final SomeClass c; const Foo({required this.a, required this.b, required this.c}); } class SomeClass { final List values; const SomeClass(this.values); } void main() { const foo1 = Foo(a: 1, b: 1, c: SomeClass([])); const foo2 = Foo(a: 1, b: 1, c: SomeClass([])); final foo3 = Foo(a: 1, b: 1, c: SomeClass([])); final foo4 = Foo(a: 1, b: 1, c: SomeClass([])); print(foo1 == foo2); // true print(foo3 == foo4); //false print(foo1.hashCode == foo2.hashCode); // true print(foo3.hashCode == foo4.hashCode); // false }
但是我们有一个大问题,我们可以将常量分配给在编译时定义的变量,但我们不能在运行时执行此操作,请参阅下面的解决方案:)

解决方案1:

需要重写 hashCode 和 == 方法,如下面的代码。

void main() { const foo1 = Foo(a: 1, b: 1, c: SomeClass([])); const foo2 = Foo(a: 1, b: 1, c: SomeClass([])); final foo3 = Foo(a: 1, b: 1, c: SomeClass([])); final foo4 = Foo(a: 1, b: 1, c: SomeClass([])); print(foo1 == foo2); // true print(foo3 == foo4); //true print(foo1.hashCode == foo2.hashCode); // true print(foo3.hashCode == foo4.hashCode); // true } class Foo { final int a; final int b; final SomeClass c; const Foo({required this.a, required this.b, required this.c}); @override int get hashCode => Object.hash(a.hashCode, b.hashCode, c.hashCode); @override bool operator ==(Object other) { return identical(this, other) || other is Foo && runtimeType == other.runtimeType && hashCode == other.hashCode; } } class SomeClass { final List values; const SomeClass(this.values); @override int get hashCode => Object.hashAll(values); @override bool operator ==(Object other) { return identical(this, other) || other is Foo && runtimeType == other.runtimeType && hashCode == other.hashCode; } }
解决方案2

(最佳解决方案)

使用

Equtable

void main() { const foo1 = Foo(a: 1, b: 1, c: SomeClass([])); const foo2 = Foo(a: 1, b: 1, c: SomeClass([])); final foo3 = Foo(a: 1, b: 1, c: SomeClass([])); final foo4 = Foo(a: 1, b: 1, c: SomeClass([])); print(foo1 == foo2); // true print(foo3 == foo4); //true print(foo1.hashCode == foo2.hashCode); // true print(foo3.hashCode == foo4.hashCode); // true } class Foo extends Equatable { final int a; final int b; final SomeClass c; const Foo({required this.a, required this.b, required this.c}); @override List<Object?> get props => [a, b, c]; } class SomeClass extends Equatable { final List values; const SomeClass(this.values); @override List<Object?> get props => [values]; }
来源:

https://www.youtube.com/watch?v=DCKaFaU4jdk

https://api.flutter.dev/flutter/dart-core/Object/hashCode.html


1
投票
在不同但相似的情况下,在框架调用检查对象之间的相等性的情况下,例如如果使用

list.toSet()

 从列表中获取唯一元素,则 
identical(this, other)
 可能不是一个选择。那时该类必须重写 
== operator
hasCode()
 方法。

但是对于这种情况,另一种方法可能是使用

equatable 包。这可以节省大量样板代码,当您有很多模型类时特别方便。


0
投票
怎么样?

final a = SomeClass(); final b = SomeClass(); // Copy one to the other. b.fromJson(a.toJson()); // Identical properties but not the same object. a.toString() == b.toString(); // true
    
© www.soinside.com 2019 - 2024. All rights reserved.