Flutter Dart类实例相等性校验及对象初始化优化咨询
问题说明
我在Flutter Dart中定义了包含多属性的CarnetWord类,并重写了==运算符与hashCode,仅通过idDico判断实例是否相等。但在使用contains方法校验相等性时,必须为CarnetWord实例填充所有属性(实际只有idDico生效);初始化类实例时也需要指定所有属性。想了解这是否正常,以及有没有优化方法?
相关类代码
class CarnetWord { @override bool operator ==(Object other) { if (identical(this, other)) return true; if (runtimeType != other.runtimeType) return false; return other is CarnetWord && other.idDico == idDico; } @override int get hashCode => idDico.hashCode; int idDico; int idCarnet; int repeatWrong; int repeatRight; int sayWrong; int sayRight; int oralTranslateWrongEng; int oralTranslateRightEng; int writtenTranslateWrongEng; int writtenTranslateRightEng; int oralTranslateWrongFr; int oralTranslateRightFr; int writtenTranslateWrongFr; int writtenTranslateRightFr; int copyRight; int copyWrong; int writeRight; int writeWrong; DateTime repeatLast; DateTime sayLast; DateTime oralTranslateLastEng; DateTime writtenTranslateLastEng; DateTime oralTranslateLastFr; DateTime writtenTranslateLastFr; DateTime copyLast; DateTime writeLast; double wordMastery; }
校验逻辑代码
for (int idDico in activite.listeMots) { if (_carnetWordBank.contains(CarnetWord( idDico: idDico, idCarnet: _carnetWordBank.length - 1, repeatWrong: 0, repeatRight: 0, sayWrong: 0, sayRight: 0, oralTranslateWrongEng: 0, oralTranslateRightEng: 0, writtenTranslateWrongEng: 0, writtenTranslateRightEng: 0, oralTranslateWrongFr: 0, oralTranslateRightFr: 0, writtenTranslateWrongFr: 0, writtenTranslateRightFr: 0, copyWrong: 0, copyRight: 0, writeWrong: 0, writeRight: 0, repeatLast: DateTime.fromMicrosecondsSinceEpoch(0), sayLast: DateTime.fromMicrosecondsSinceEpoch(0), oralTranslateLastEng: DateTime.fromMicrosecondsSinceEpoch(0), writtenTranslateLastEng: DateTime.fromMicrosecondsSinceEpoch(0), oralTranslateLastFr: DateTime.fromMicrosecondsSinceEpoch(0), writtenTranslateLastFr: DateTime.fromMicrosecondsSinceEpoch(0), copyLast: DateTime.fromMicrosecondsSinceEpoch(0), writeLast: DateTime.fromMicrosecondsSinceEpoch(0), wordMastery: 0)) == true) { _list.add(_carnetWordBank .firstWhere((element) => element.idDico == idDico) .idCarnet); }
解答
这是正常现象吗?
是正常的。因为当前CarnetWord类没有定义带默认参数的构造函数,Dart会要求初始化所有非空属性(null安全模式下甚至会直接报错)。而contains方法需要传入完整的类实例,所以你不得不填充所有属性,哪怕这些属性在相等判断中不起作用。
优化方法
1. 给类添加带默认值的构造函数
修改CarnetWord的构造函数,给除idDico外的所有属性设置默认值,这样初始化时仅需传入idDico:
class CarnetWord { @override bool operator ==(Object other) { if (identical(this, other)) return true; if (runtimeType != other.runtimeType) return false; return other is CarnetWord && other.idDico == idDico; } @override int get hashCode => idDico.hashCode; final int idDico; final int idCarnet; final int repeatWrong; final int repeatRight; final int sayWrong; final int sayRight; final int oralTranslateWrongEng; final int oralTranslateRightEng; final int writtenTranslateWrongEng; final int writtenTranslateRightEng; final int oralTranslateWrongFr; final int oralTranslateRightFr; final int writtenTranslateWrongFr; final int writtenTranslateRightFr; final int copyRight; final int copyWrong; final int writeRight; final int writeWrong; final DateTime repeatLast; final DateTime sayLast; final DateTime oralTranslateLastEng; final DateTime writtenTranslateLastEng; final DateTime oralTranslateLastFr; final DateTime writtenTranslateLastFr; final DateTime copyLast; final DateTime writeLast; final double wordMastery; // 带默认参数的构造函数 CarnetWord({ required this.idDico, this.idCarnet = 0, this.repeatWrong = 0, this.repeatRight = 0, this.sayWrong = 0, this.sayRight = 0, this.oralTranslateWrongEng = 0, this.oralTranslateRightEng = 0, this.writtenTranslateWrongEng = 0, this.writtenTranslateRightEng = 0, this.oralTranslateWrongFr = 0, this.oralTranslateRightFr = 0, this.writtenTranslateWrongFr = 0, this.writtenTranslateRightFr = 0, this.copyRight = 0, this.copyWrong = 0, this.writeRight = 0, this.writeWrong = 0, DateTime? repeatLast, DateTime? sayLast, DateTime? oralTranslateLastEng, DateTime? writtenTranslateLastEng, DateTime? oralTranslateLastFr, DateTime? writtenTranslateLastFr, DateTime? copyLast, DateTime? writeLast, this.wordMastery = 0.0, }) : repeatLast = repeatLast ?? DateTime.fromMicrosecondsSinceEpoch(0), sayLast = sayLast ?? DateTime.fromMicrosecondsSinceEpoch(0), oralTranslateLastEng = oralTranslateLastEng ?? DateTime.fromMicrosecondsSinceEpoch(0), writtenTranslateLastEng = writtenTranslateLastEng ?? DateTime.fromMicrosecondsSinceEpoch(0), oralTranslateLastFr = oralTranslateLastFr ?? DateTime.fromMicrosecondsSinceEpoch(0), writtenTranslateLastFr = writtenTranslateLastFr ?? DateTime.fromMicrosecondsSinceEpoch(0), copyLast = copyLast ?? DateTime.fromMicrosecondsSinceEpoch(0), writeLast = writeLast ?? DateTime.fromMicrosecondsSinceEpoch(0); }
此时使用contains只需写:
_carnetWordBank.contains(CarnetWord(idDico: idDico))
2. 添加静态工厂方法快速生成判断用实例
如果不想修改主构造函数,可以添加静态方法专门生成用于相等判断的实例:
class CarnetWord { // ... 原有代码 ... static CarnetWord forEqualityCheck(int idDico) { return CarnetWord( idDico: idDico, idCarnet: 0, repeatWrong: 0, repeatRight: 0, // 其他属性按默认值填充 repeatLast: DateTime.fromMicrosecondsSinceEpoch(0), wordMastery: 0.0 // ... 省略其余默认属性赋值 ... ); } }
使用时直接调用:
_carnetWordBank.contains(CarnetWord.forEqualityCheck(idDico))
3. 用any方法替代contains(推荐)
这是最简洁高效的方式,无需创建任何CarnetWord实例,直接遍历列表判断是否存在匹配的idDico:
for (int idDico in activite.listeMots) { if (_carnetWordBank.any((word) => word.idDico == idDico)) { _list.add(_carnetWordBank.firstWhere((element) => element.idDico == idDico).idCarnet); } }
若列表元素较多,可提前构建idDico到CarnetWord的映射,避免重复遍历查找:
// 提前构建映射表 final idToCarnetWord = Map.fromEntries( _carnetWordBank.map((word) => MapEntry(word.idDico, word)), ); for (int idDico in activite.listeMots) { final word = idToCarnetWord[idDico]; if (word != null) { _list.add(word.idCarnet); } }
内容的提问来源于stack exchange,提问作者SylvainJack
相关产品推荐
相关产品推荐

