有人同意这段代码的输出令人惊讶吗?
如果是这样,谁能解释一下正在发生的事情。 为什么add(499)
会产生三个具有价值499
的新元素,而不仅仅是一个?
shared[0]
具有类型List<int>
因此对shared[0]
执行的添加应该对shared[1]
没有影响。
// output is
[[], [], []]
[[499, 599], [499, 599], [499, 599]]
499
599
499
599
499
599
飞镖程序:
main()
{
var xx = <int>[];
final shared = List.filled(3, xx);
print(shared);
shared[0].add(499);
shared[1].add(599);
print(shared);
for (int k = 0; k < shared.length; ++k) {
for (int j = 0; j < shared[k].length; ++j)
print(shared[k][j]);
}
}
shared[0]
具有类型List<int>
因此对shared[0]
执行的添加应该对shared[1]
没有影响。
shared[0]
List<int>
的事实与以下事实正交:shared[0]
和shared[1]
都是对您在第 1 行创建的同一单个List<int>
的对象引用:var xx = <int>[];
。
让我们逐行进行:
-
var xx = <int>[];
- 这会在程序中创建一个新的空的、可调整大小的
List<int>
对象。- 我不是 Dart 用户,但据我所知,这个对象将存在于 Dart 的 GC 堆上,就像 C# 中的
new List<int>()
或 Java 中的new ArrayList<Integer>()
一样 - 并且存在于 GC 堆上的对象可以具有来自程序其他地方的任意数量的入站引用。
- 我不是 Dart 用户,但据我所知,这个对象将存在于 Dart 的 GC 堆上,就像 C# 中的
- 这会在程序中创建一个新的空的、可调整大小的
-
final shared = List.filled(3, xx);
- 这将创建第二个新的
List<List<int>>
对象,初始大小为3
,这 3 个元素中的每一个都是对传递到filled
xx
对象的引用。 final
修饰符只是意味着不能重新分配shared
变量(对象引用)。这并不意味着shared
是不可变的对象或以任何方式只读,也不赋予对象引用复制语义或值语义。
- 这将创建第二个新的
-
print(shared);
- 这将打印"
[[], [], []]
",因为此时,xx
列表仍然是空的。
- 这将打印"
-
shared[0].add(499);
- 此时,
xx
列表仍为空,因此调用.add(499)
会将第一个值添加到xx
中。 - 如果你用调试器查看,这将立即在
shared[1]
、shared[2]
和xx
中可见。 - 证明所有这些对象引用都指向同一对象的另一种方法是使用
identical()
。
- 此时,
-
shared[1].add(599);
- 同样,这与执行
shared[2].add(599)
或xx.add(599)
相同。
- 同样,这与执行
-
print(shared);
- 这打印"
[[499, 599], [499, 599], [499, 599]]
"。 - 也许相反,将打印输出视为"
[xx, xx, xx]
"。
- 这打印"
-
for (int k = 0; k < shared.length; ++k) for (int j = 0; j < shared[k].length; ++j) print(shared[k][j]);
- 这实际上与
print(shared)
相同,除了将每个嵌套元素呈现在自己的行上,从而隐藏列表的嵌套结构。 - 如果将
print
调用站点更改为如下所示的内容:print( "k: $k, j: $j == ${shared[k][j]}");
,您将获得更容易理解的输出:k: 0, j: 0 == 499 k: 0, j: 1 == 599 k: 1, j: 0 == 499 k: 1, j: 1 == 599 k: 2, j: 0 == 499 k: 2, j: 1 == 599
- 这实际上与
通过复制+粘贴以下代码来 Dartpad.dev,请亲自查看:
main()
{
var xx = <int>[];
final shared = List.filled(3, xx);
print(shared);
shared[0].add(499);
shared[1].add(599);
print(shared);
print("");
for (int k = 0; k < shared.length; ++k) {
for (int j = 0; j < shared[k].length; ++j) {
print( "k: $k, j: $j == ${shared[k][j]}");
}
}
print("");
var areReferencesToSameObject_xx_0 = identical(xx, shared[0]);
var areReferencesToSameObject_xx_1 = identical(xx, shared[1]);
var areReferencesToSameObject_xx_2 = identical(xx, shared[2]);
var areReferencesToSameObject_1_2 = identical(shared[1], shared[2]);
var areReferencesToSameObject_xx_shared = identical(xx, shared);
print("xx and shared[0] are the same object: $areReferencesToSameObject_xx_0"); // true
print("xx and shared[1] are the same object: $areReferencesToSameObject_xx_1"); // true
print("xx and shared[2] are the same object: $areReferencesToSameObject_xx_2"); // true
print("shared[1] and shared[2] are the same object: $areReferencesToSameObject_1_2"); // true
print("shared and xx are the same object: $areReferencesToSameObject_xx_shared"); // false
}
给我这个输出:
[[], [], []]
[[499, 599], [499, 599], [499, 599]]
k: 0, j: 0 == 499
k: 0, j: 1 == 599
k: 1, j: 0 == 499
k: 1, j: 1 == 599
k: 2, j: 0 == 499
k: 2, j: 1 == 599
xx and shared[0] are the same object: true
xx and shared[1] are the same object: true
xx and shared[2] are the same object: true
shared[1] and shared[2] are the same object: true
shared and xx are the same object: false