You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Dart List.filled创建嵌套列表调用add为何子列表同步变化?

运行结果反常的核心原因

这个结果确实违背很多开发者的直觉,问题根源在于对Dart的List.filled构造方法行为理解有误:

  • List.filled(int length, E fill)的核心逻辑是:创建固定长度为length的列表,所有下标位置存储的都是同一个fill对象的引用,构造过程不会为每个位置生成fill对象的独立副本。
  • 你的代码中首先创建了一个空列表实例xx,随后调用List.filled(3, xx)时,shared列表的三个位置shared[0]、shared[1]、shared[2]存储的全是指向这同一个xx实例的引用,并不存在三个独立的子列表。

你对shared[0]或shared[1]调用add方法时,本质都是在操作内存里那唯一的一个xx列表实例,自然三个下标位置读出来的内容会完全同步变化,看起来就像改一个位置所有子列表都跟着变。

代码执行流程拆解

  1. 执行var xx = <int>[];:内存中开辟空间创建一个空的int类型列表,变量xx持有这个实例的引用。
  2. 执行final shared = List.filled(3, xx);:创建长度为3的列表shared,三个元素全部存入xx持有的列表引用,此时三个下标指向的都是同一个空列表,第一次打印输出[[], [], []]。
  3. 执行shared[0].add(499);:取出shared[0]存储的引用(也就是最开始创建的xx实例),向该列表中添加元素499,此时这个唯一的列表内容变为[499],三个下标读取到的列表内容自然同步更新。
  4. 执行shared[1].add(599);:取出shared[1]存储的同一个列表引用,向其中添加元素599,此时列表内容变为[499, 599],第二次打印时三个子列表自然全是这个内容,后续遍历打印的元素顺序也和输出完全匹配。
正确实现方式

如果你的需求是创建包含3个独立空子列表的二维列表,需要使用List.generate构造方法,它会为每个下标单独执行生成逻辑,创建独立的实例:

main()
{
  // 每个下标位置都会生成一个全新的空列表,三个子列表完全独立互不影响
  final shared = List.generate(3, (index) => <int>[]);
  print(shared); // 输出 [[], [], []]
  shared[0].add(499);
  shared[1].add(599);
  print(shared); // 输出 [[499], [599], []],符合常规直觉
}

注意:List.filled仅适合填充int、String、bool这类不可变的值类型。如果要填充列表、自定义类实例等引用类型,除非明确需要所有位置共享同一个实例,否则不要使用List.filled,否则很容易出现这种一改全改的非预期bug。

内容的提问来源于stack exchange,提问作者Alpha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 18:15:57