You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 09:40:17