文章开始我们先假设有这样一个业务类:

class Model{
    int id;
}
1
2
3

有两个业务对象:

var model1=Model()..id=1;
var model2=Model()..id=1;
print(model1==model2);  //打印false
print(1==1);			//打印true
1
2
3
4

​ 上面代码我们创建了mode1与mode2两个业务对象,并对id赋值为相同的1,但是当我们比较model1与model2的时候发现其并不相等,其实这都在我们的意料之中,因为在我们创建Model的实例时dart会去申请不同的内存区域来初始化对象,所以从dart引擎的角度来看model1与mode2确实是两块内存区域,而对于1==1的比较dart是通过字面量来进行比较的,也就是直接比较他们的值而不是内存地址,即使比较地址也是相同的,通常字面量类型只会在内存中保留一份实例。

​ 但对于业务对象来说,我们通常希望他们是相等的,那么我们只能通过比较model1.id==model2.id才能保证它们相等,这样做虽然保证了对象的具有相同的业务意义,但是我们无法在Set,Map这样的集合中使用。

​ 幸好,dart给我们提供类==操作符的重载来让我们自定义比较两个业务对象的相等性。

# operator ==

class Model{
  int id;
  operator ==(other){
    return id==other.id;
  }
}
var model1=Model()..id=1;
var model2=Model()..id=1;
print(model1==model2) //打印true
1
2
3
4
5
6
7
8
9
10
11

​ 上面代码我们通过重载==操作符就实现了之前我们我们对业务对象的比较,看似没有什么问题,但当我们在Set,Map这样的去重集合中添加元素似则发现跟我们的预期有点偏差,为什么呢?想要明白这点通常我们需要了解Set,Map是如何去重元素的。

# hashCode

​ dart文档中提示我们,当重写==操作符时应该先重写hashCode,这并不是必须的,你也可以仅重写它们之中的任何一个,这样并不会发生编译错误,不过我们也无法在Set,Map中得到预期的结果,所以同时重写==与hashCode才是正确的做法,因为Set,Map对元素的比较首先通过比较hashCode来判断元素是否在同一个hash表中,然后再通过==操作符判断元素是否相等。

class Model {
  int id;
  
  int get hashCode {
    print("先从hash表中查找对应的元素");
    // hashCode并不要求一定是唯一的,你应该根据自己的业务需要定义
    // 但是hashCode重复的越少越能增加匹配速度
    return id;
  }
  operator ==(other) {
    print("然后通过==比较元素是否相等");
    // 确保other是一个Model类型
    if(other is! Model){
        return false;
    }
    return id == other.id;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

验证结果是否符合预期

  var model1 = Model()..id = 1;
  var model2 = Model()..id = 1;
  Set<Model> models = Set();
  models.add(model1);
  models.add(model2);
  Map<Model, Model> modelMap = Map();
  modelMap.putIfAbsent(model1, () => model1);
  modelMap.putIfAbsent(model2, () => model2);
  print([models.length, modelMap.length]);  //打印[1,1]
1
2
3
4
5
6
7
8
9
10
11