Dart增强枚举作为Map键时抛出无法修改不可变Map异常
异常原因
这个报错和枚举从扩展方法迁移到增强枚举没有直接关系,触发点有两个:
VgnItmCache是freezed生成的不可变类,默认所有属性都是final,且freezed会对传入的集合类型参数做不可变包装,直接修改实例上的集合属性本身就违反freezed的设计约定。- 你在
$localFetch中通过Map.map()生成的populatedVgnItms本身就是不可修改的Map视图:Dart中Map.map()、集合的toMap()这类转换方法默认返回的都是不可修改集合,你将这个Map通过copyWith传入后,freezed不会主动将其转为可修改集合,后续执行下标赋值操作时就会抛出Cannot modify unmodifiable map错误。
修复方法
优先推荐符合freezed不可变设计的方案,不要强行修改集合的可变性破坏数据一致性:
方案1(推荐):通过copyWith返回新实例
修改setVgnItm方法,不要直接修改原有实例的vgnItms属性,而是基于原有值生成新Map,再通过copyWith返回更新后的新缓存实例:
VgnItmCache setVgnItm({required VgnItm vgnItm, VgnItmType? type}) { final theType = type ?? myVgnItmType; // 复制原有Map为可修改的新实例 final updatedVgnItms = Map<VgnItmType, VgnItmEst>.from(vgnItms ?? const {}); updatedVgnItms[theType] = updatedVgnItms[theType]!.copyWith(vgnItm: vgnItm); // 返回更新后的新缓存实例,调用方需要用这个新实例替换旧实例 return copyWith(vgnItms: updatedVgnItms); }
方案2:显式声明可变集合(不推荐,破坏不可变特性)
如果你确实需要直接修改实例上的Map属性,需要做两处修改:
- 生成
populatedVgnItms时主动将其转为可修改Map:
final populatedVgnItms = Map<VgnItmType, VgnItmEst>.from( VgnItmType.items.map((k, v) { return MapEntry(k, cache.vgnItms?[k] ?? VgnItmEst.empty(k)); }) );
- 给
vgnItms字段添加@Mutable()注解,告诉freezed不要对这个字段做不可变包装:
const factory VgnItmCache( { @Mutable() Map<VgnItmType, VgnItmEst>? vgnItms, @Default(<S3ImageCommand>[]) List<S3ImageCommand> s3ImageCommands, Option? vgnItmType, FormType? formType, @JsonKey(ignore: true) Ref? provider}) = _VgnItmCache;
额外提示:你迁移后的增强枚举代码中,静态
itemsMap的两个元素之间缺少分隔逗号,会触发语法错误,记得补上。
内容的提问来源于stack exchange,提问作者BeniaminoBaggins
相关产品推荐
相关产品推荐

