Dart中List直接赋值与使用...扩展运算符拷贝列表的区别
两种Dart列表赋值写法的核心差异
两种写法的本质区别就是「引用同个对象」和「创建新对象」的区别,没有复杂概念:
1. 直接赋值 List newData = data;
这行代码没有做任何拷贝操作,只是让newData和data两个变量指向内存里完全相同的同一个列表实例。
你对任意一个变量做列表层面的修改——比如增删元素、重新排序、清空列表,两个变量读到的结果都会同步变化,本质上操作的从来都是同一个对象。
List data = [1, 2, 3]; List newData = data; newData.add(4); print(data); // 输出 [1, 2, 3, 4],原列表被同步修改
2. 展开运算符赋值 List newData = [...data];
这里的...是Dart的集合展开运算符,这行代码会创建一个全新的空列表,再把原data里的所有元素按顺序挨个塞进新列表里,最终newData和data是两个完全独立的列表实例。
这时候你对newData做增删元素、重排、清空这类列表层面的操作,完全不会影响到原data。
List data = [1, 2, 3]; List newData = [...data]; newData.add(4); print(data); // 输出 [1, 2, 3],原列表不受任何影响 print(newData); // 输出 [1, 2, 3, 4]
必须注意的浅拷贝坑
展开运算符实现的是浅拷贝,不是深拷贝。
拿你示例里存Map的列表来说:新列表只是把原列表里存的元素引用抄了一遍,列表里装的那些Map对象本身还是同一份。如果你修改新列表里嵌套对象的属性,原列表里对应的值还是会同步变:
List data = [ {'value': 'value one'}, {'value': 'value two'}, ]; List newData = [...data]; // 修改新列表里嵌套Map的属性 newData[0]['value'] = 'modified'; print(data[0]['value']); // 输出 modified,原列表的嵌套对象还是被改了
如果需要完全不互相影响的深拷贝,得手动遍历列表,把每一层的嵌套对象也都拷贝一份,单靠展开运算符做不到。
选型参考
- 只是给现有列表起个别名,不需要独立修改新列表的结构,直接用
=赋值就行,没有额外性能开销 - 需要基于原列表生成独立的新列表,做增删、排序等操作不影响原数据,就用
...展开(List.of(data)、data.toList()和它的效果完全一致) - 存在嵌套对象、需要完全隔离修改影响,自行实现深拷贝逻辑
内容的提问来源于stack exchange,提问作者CCP
相关产品推荐
相关产品推荐

