在Dart中,如何比较两个对象以确定它们是否是同一个示例?

ubby3x7f  于 2023-03-27  发布在  其他
关注(0)|答案(7)|浏览(165)

假设我有一个类,有很多示例变量,我想重载==操作符(和hashCode),这样我就可以在Map中使用示例作为键。

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类提供的==操作符来完成此操作?

xmakbtuz

xmakbtuz1#

这是我比较deep 2对象的方式,它们不一样:

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
b1payxdu

b1payxdu2#

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

如果某个类Foo不 * 覆盖==,那么默认实现是返回它们是否是同一个对象。documentation声明:
所有对象的默认行为是当且仅当此对象和其他对象是同一对象时返回true。

rsaldnfx

rsaldnfx3#

在不同但类似的注意事项中,在框架调用检查对象之间的相等性的情况下,例如在list.toSet()从列表中获取唯一元素的情况下,identical(this, other)可能不是一个选择。此时类必须覆盖== operatorhasCode()方法。
然而,对于这种情况,另一种方法是使用equatable包,这节省了大量的代码,当你有很多模型类时特别方便。

mepcadol

mepcadol4#

可以使用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 *
mo49yndu

mo49yndu5#

当你试图比较两个通过引用传递的对象,比如class,List,Map,Set等...你需要将变量设置为常量变量才能比较它们,因为编译器通过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

6ovsh4lw

6ovsh4lw6#

您正在查找“identical“,它将检查2个示例是否相同。

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
}

相关问题