Flutter-Dart中如何创建嵌套动态Map的完全独立副本?
Flutter/Dart 中动态嵌套Map/List的深拷贝方案
我在Flutter-Dart项目中遇到一个问题:服务器返回了一个包含多层嵌套Map和List的动态数据myMap,结构和长度都无法预先确定,示例如下:
Map<String, dynamic> myMap = { 'key': { 'key': [1, 2, 3], 'key2': { 'key': 23, 'subKey': { 'nestedKey': [ 4, 5, { 'deepKey': { 'finalList': [ 9, 10, { 'ultraKey': [11, 12] } ] } } ] } } }, 'key2': { 'key': [ 1, 2, 3, { 'dsf': [ 1, 2, { 'superKey': [ 3, 4, { 'megaKey': [5, 6] } ] } ] } ], 'key2': { 'key': 23, 'fdasd': [ { 'nestedList': [ 7, 8, { 'deepKey': { 'finalList': [ 9, 10, { 'ultraKey': [ 11, 12, { 'ultimateKey': [13, 14] } ] } ] } } ] } ] } } };
我需要创建一个和myMap完全独立的副本myMap2,但直接赋值myMap2 = myMap会产生引用,修改其中一个会影响另一个;用Map.of(myMap)这种浅拷贝也只能处理顶层结构,嵌套的List和Map还是共享引用。
目前我用手动递归的方式实现深拷贝:
Map deepCopy(Map original) { Map copy = {}; original.forEach((key, value) { if (value is Map) { copy[key] = Map.of(deepCopy(value)); } else if (value is List) { copy[key] = List.of(deepCopy2(value)); } else { copy[key] = value; } }); return copy; } List deepCopy2(List original) { List copy = []; for (var value in original) { if (value is Map) { copy.add(Map.of(deepCopy(value))); } else if (value is List) { copy.add(List.of(deepCopy2(value))); } else { copy.add(value); } } return copy; } Map myMap2 = deepCopy(myMap);
但考虑到数据的动态性,这个方案不够简洁。我也考虑过用jsonDecode(jsonEncode(data))实现深拷贝,但担心存在JSON不支持的类型,需要额外处理toEncodable参数。想请教有没有更简洁高效的方法,能确保所有嵌套结构完全独立?
解决方案
1. 优化手动递归代码
可以把两个递归函数合并成一个,用泛型处理所有类型,代码更简洁且覆盖所有场景:
dynamic deepCopy(dynamic value) { if (value is Map) { // 遍历Map的每个键值对,递归拷贝值 return value.map((key, val) => MapEntry(key, deepCopy(val))); } else if (value is List) { // 遍历List的每个元素,递归拷贝 return value.map((val) => deepCopy(val)).toList(); } else { // 基础类型(int、String、bool等)都是不可变的,直接返回即可 return value; } } // 使用方式 final myMap2 = deepCopy(myMap) as Map<String, dynamic>;
这个版本的优势:
- 统一处理Map、List和基础类型,无需拆分两个函数
- 基础类型直接返回,因为它们是不可变类型,修改不会影响原数据
- 自动处理任意深度的嵌套结构
2. JSON序列化方案(适合纯JSON兼容类型)
如果服务器返回的所有数据都是JSON支持的类型(String、int、double、bool、List、Map),那么jsonDecode(jsonEncode(myMap))是最简洁的实现方式:
import 'dart:convert'; final myMap2 = jsonDecode(jsonEncode(myMap)) as Map<String, dynamic>;
注意事项:
- 如果数据包含自定义类型,需要在
jsonEncode时指定toEncodable来处理:final myMap2 = jsonDecode(jsonEncode(myMap, toEncodable: (obj) { if (obj is CustomModel) { return obj.toJson(); // 自定义类型需实现toJson方法 } throw UnsupportedError('无法编码类型:${obj.runtimeType}'); })) as Map<String, dynamic>; - JSON序列化会丢失非String类型的键(比如Map的键是int的话,会被转为String),如果有这种场景不适合用此方法。
3. 使用第三方包(快速实现)
如果项目允许引入第三方包,可以使用deep_collection包,它封装了完善的深拷贝逻辑:
首先在pubspec.yaml中添加依赖:
dependencies: deep_collection: ^1.0.0
然后使用:
import 'package:deep_collection/deep_collection.dart'; final myMap2 = myMap.deepCopy();
第三方包的优势是无需自己维护递归逻辑,已经处理了各种边缘场景,适合快速开发。
总结
- 纯JSON兼容数据:优先用
jsonDecode(jsonEncode(...)),代码最简洁 - 需要保留类型或有自定义类型:使用优化后的手动递归方案,可靠且可控
- 允许第三方包:用
deep_collection这类成熟包,省心高效
内容的提问来源于stack exchange,提问作者Mohammed Hamdan
相关产品推荐
相关产品推荐

