【发布时间】:2014-03-11 18:07:36
【问题描述】:
来自 Java 背景:“克隆” Dart List、Map 和 Set 的推荐方法是什么?
【问题讨论】:
-
我打算在这里添加我自己的答案,但我把它变成了一篇文章:Cloning lists, maps, and sets in Dart
标签: collections dart clone
来自 Java 背景:“克隆” Dart List、Map 和 Set 的推荐方法是什么?
【问题讨论】:
标签: collections dart clone
在 Java 中使用 clone() 是棘手且值得怀疑的1,2。实际上,clone() 是一个复制构造函数,为此,Dart 的 List、Map 和 Set 类型都有一个名为 .from() 的 named constructor,它们执行 shallow copy;例如鉴于这些声明
Map<String, int> numMoons, moreMoons;
numMoons = const <String,int>{ 'Mars' : 2, 'Jupiter' : 27 };
List<String> planets, morePlanets;
你可以像这样使用.from():
moreMoons = new Map<String,int>.from(numMoons)
..addAll({'Saturn' : 53 });
planets = new List<String>.from(numMoons.keys);
morePlanets = new List<String>.from(planets)
..add('Pluto');
请注意,List.from() 更普遍地接受迭代器,而不仅仅是 List。
为了完整起见,我应该提到dart:html Node 类定义了一个clone() 方法。
1 J. Bloch,“Effective Java”第 2 版,第 11 条。
2B. Venners, "Josh Bloch on Design: Copy Constructor versus Cloning", 2002。从这里引用3。引用文章:
如果你读过我书中关于克隆的内容,特别是如果你读到字里行间,你就会知道我认为克隆被严重破坏了。 ---J.布洛赫
【讨论】:
.from() 是一个 shallow 复制构造函数。为了清楚起见,我从未说过.from() 执行了克隆操作。我写的是clone() 是一种复制构造函数。
List 的类型,List<E>.of() 可能会更好。
使用新版本的 dart 克隆地图或列表变得非常容易。 您可以尝试使用此方法对 List 和 Map 进行深度克隆。
对于列表
List a = ['x','y', 'z'];
List b = [...a];
用于地图
Map mapA = {"a":"b"};
Map mapB = {...mapA};
套装
Set setA = {1,2,3,};
Set setB = {...setA};
我希望有人觉得这很有帮助。
【讨论】:
如果您使用的是 dart > 2.3.0,您可以使用扩展运算符,例如:
List<int> a = [1,2,3];
List<int> b = [...a]; // copy of a
【讨论】:
List,因为有方括号。一般技术适用于Sets 或Maps:{...set} 或{...map}。
对于列表和集合,我通常使用
List<String> clone = []..addAll(originalList);
正如@kzhdev 提到的,需要注意的是addAll() 和from()
[不要] 真的克隆。他们在新的 Map/List/Set 中添加了一个引用。
这对我来说通常没问题,但我会记住这一点。
【讨论】:
对于深拷贝(克隆),您可以使用:
Map<String, dynamic> src = {'a': 123, 'b': 456};
Map<String, dynamic> copy = json.decode(json.encode(src));
但可能对性能有些担忧。
【讨论】:
Map.from() 仅适用于一维地图。
在dart中复制多维地图使用以下方法
Map<keyType, valueType> copyDeepMap( Map<keyType, valueType> map )
{
Map<keyType, valueType> newMap = {};
map.forEach
(
(key, value)
{
newMap[key] =( value is Map ) ? copyDeepMap(value) : value ;
}
);
return newMap;
}
【讨论】:
这个解决方案应该有效:
List list1 = [1,2,3,4];
List list2 = list1.map((element)=>element).toList();
它适用于列表,但应该适用于地图等,如果最后是列表,请记住添加到列表中
【讨论】:
对我来说最好的解决方案:
List temp = {1,2,3,4}
List platforms = json.decode(json.encode(parent.platforms));
【讨论】:
这是我的解决方案。我希望它可以帮助某人。
factory Product.deepCopy(Product productToCopy) => new Product(
productToCopy.id,
productToCopy.title,
productToCopy.description,
productToCopy.price,
productToCopy.imageUrl,
productToCopy.isFavorite,
);}
【讨论】:
要复制 Map
var filteredNewCopy = filtered.map((key, value) => MapEntry(key, [...value]));
【讨论】:
没有 100% 防弹的方法来制作精确的独立副本,但 answer from Manish Dhruw 非常好。但是,它仅适用于包含简单变量类型和嵌套 Maps 的 Maps。
要将其扩展为也适用于其他常见集合,例如List 和Set,以及它们的组合,您可以使用类似于下面的代码。
您实际上并不需要 DeepCopyable 类,但如果您想使用这些函数轻松地使自己的类“可深度复制”,它会很有用。
abstract class DeepCopyable{
T deepCopy<T>();
}
List<T> listDeepCopy<T>(List list){
List<T> newList = List<T>();
list.forEach((value) {
newList.add(
value is Map ? mapDeepCopy(value) :
value is List ? listDeepCopy(value) :
value is Set ? setDeepCopy(value) :
value is DeepCopyable ? value.deepCopy() :
value
);
});
return newList;
}
Set<T> setDeepCopy<T>(Set s){
Set<T> newSet = Set<T>();
s.forEach((value) {
newSet.add(
value is Map ? mapDeepCopy(value) :
value is List ? listDeepCopy(value) :
value is Set ? setDeepCopy(value) :
value is DeepCopyable ? value.deepCopy() :
value
);
});
return newSet;
}
Map<K,V> mapDeepCopy<K,V>(Map<K,V> map){
Map<K,V> newMap = Map<K,V>();
map.forEach((key, value){
newMap[key] =
value is Map ? mapDeepCopy(value) :
value is List ? listDeepCopy(value) :
value is Set ? setDeepCopy(value) :
value is DeepCopyable ? value.deepCopy() :
value;
});
return newMap;
}
正如我所提到的,它显然仍然不是 100% 防弹 - 例如,您将丢失嵌套集合的类型信息。
【讨论】:
给出的答案很好,但请注意 generate 构造函数,如果您想“增长”一个固定长度的列表,它会很有帮助,例如:
List<String> list = new List<String>(5);
int depth = 0; // a variable to track what index we're using
...
depth++;
if (list.length <= depth) {
list = new List<String>.generate(depth * 2,
(int index) => index < depth ? list[index] : null,
growable: false);
}
【讨论】: