Flutter列表增删自定义对象时contains方法失效如何解决
问题根因
Dart中contains方法默认对自定义对象/集合类型判断的是内存引用相等,而非值相等:
- 你每次调用
{teacherId, subjectId}都会生成一个全新的Set对象,哪怕两个Set的内容完全一致,内存地址也不同,所以contains永远返回false - 如果你用的
Teachers、Subjectt是自定义实体类,没有重写==运算符和hashCode的话,即使内容相同的类实例也会被判定为不同对象
可行解决方案
下面提供三种不同复杂度的实现方案,可根据自己的需求选择:
方案1:用组合唯一键(最简便,无需改实体类)
直接将教师和学科的唯一ID拼接为字符串存储,字符串的contains是值判断,不会有引用问题:
// 改列表类型为String,存储格式示例:["1_2", "4_9"] List<String> selectedList = []; void addTeacher(Teachers teacher, Subjectt subject) { // 用两个实体的唯一ID拼接成唯一键,注意替换.id为你实际的主键字段名 String uniqueKey = '${teacher.id}_${subject.id}'; if (selectedList.contains(uniqueKey)) { selectedList.remove(uniqueKey); myColor = Colors.grey; print('removed teacher => ${teacher.toString()}'); } else { selectedList.add(uniqueKey); myColor = AsasColors().blue; print('added teacher => ${teacher.toString()}'); } notifyListeners(); print(selectedList); }
方案2:自定义数据类(最规范,适合后续扩展)
定义专门的存储类,重写==和hashCode,让contains按照内容判断:
// 第一步:定义存储实体类 class SelectedRelation { final Teachers teacher; final Subjectt subject; SelectedRelation({required this.teacher, required this.subject}); // 重写==:只要教师ID和学科ID都相同就判定为同一个对象 @override bool operator ==(Object other) => identical(this, other) || other is SelectedRelation && runtimeType == other.runtimeType && teacher.id == other.teacher.id && subject.id == other.subject.id; // 重写hashCode,和==规则保持一致 @override int get hashCode => Object.hash(teacher.id, subject.id); } // 第二步:修改列表和方法 List<SelectedRelation> selectedList = []; void addTeacher(Teachers teacher, Subjectt subject) { final target = SelectedRelation(teacher: teacher, subject: subject); if (selectedList.contains(target)) { selectedList.remove(target); myColor = Colors.grey; print('removed teacher => ${teacher.toString()}'); } else { selectedList.add(target); myColor = AsasColors().blue; print('added teacher => ${teacher.toString()}'); } notifyListeners(); print(selectedList); }
如果项目中引入了equatable库,也可以直接继承Equatable省略手动重写的步骤。
方案3:手动遍历判断(无需修改现有存储结构)
如果你不想改动现有的Set存储逻辑,可以自己遍历列表匹配内容,绕过默认的contains判断:
List<dynamic> selectedList = []; void addTeacher(Teachers teacher, Subjectt subject) { // 遍历查找内容匹配的Set final existIndex = selectedList.indexWhere((item) { if (item is! Set) return false; // 匹配Set内的教师和学科,替换.id为你实际的主键字段名 final hasTeacher = item.any((e) => e is Teachers && e.id == teacher.id); final hasSubject = item.any((e) => e is Subjectt && e.id == subject.id); return hasTeacher && hasSubject; }); if (existIndex != -1) { selectedList.removeAt(existIndex); myColor = Colors.grey; print('removed teacher => ${teacher.toString()}'); } else { selectedList.add({teacher, subject}); myColor = AsasColors().blue; print('added teacher => ${teacher.toString()}'); } notifyListeners(); print(selectedList); }
内容的提问来源于stack exchange,提问作者Faris Shomali
相关产品推荐
相关产品推荐

