我看了一下 D2 中的动态数组,发现它们很难理解。我似乎也错误地解释了规范。在更改数组时,处理动态数组的引用或切片似乎很容易出错......或者我只是不了解基本原理?
引用同一个数组只共享实际项目:
auto a = [1];
auto b = a;
assert(&a != &b); // different instance; Doesn't share length
assert(a.ptr == b.ptr); // same items
assert(a == [1]);
assert(a == b);
当它们引用相同的数组时,更改一个会更改另一个:
auto a = [1,2];
auto b = a;
a[1] = 20;
assert(a == [1,20]);
assert(a == b);
从数组规范
为了最大限度地提高效率,运行时总是尝试调整数组的大小以避免额外的复制。如果新大小更大并且数组不是通过 new 运算符或先前的调整大小操作分配的,它将始终进行复制。
所以改变长度并不一定会破坏参考:
auto a = [1];
auto b = a;
b.length = 2;
assert(b == [1,0]);
assert(a == [1]); // a unchanged even if it refers to the same instance
assert(a.ptr == b.ptr); // but still the same instance
// So updates to one works on the other
a[0] = 10;
assert(a == [10]);
assert(b == [10,0]);
从数组规范
连接总是会创建其操作数的副本,即使其中一个操作数是长度为 0 的数组
auto a = [1];
auto b = a;
b ~= 2; // Should make a copy, right..?
assert(a == [1]);
assert(b == [1,2]);
assert(a != b);
assert(a4.ptr == b.ptr); // But it's still the same instance
a[0] = 10;
assert(b == [10,2]); // So changes to a changes b
但是当数组相互踩踏时,这些值将被复制到一个新位置并且引用被破坏:
auto a = [1];
auto b = a;
b ~= 2;
assert(a == [1]);
assert(b == [1,2]);
a.length = 2; // Copies values to new memory location to not overwrite b's changes
assert(a.ptr != b.ptr);
在进行更改之前更改两个数组的长度会产生与上述相同的结果(鉴于上述情况,我希望如此):
auto a = [1];
auto b = a;
a.length = 2;
b.length = 2;
a[1] = 2;
assert(a == [1,2]);
assert(b == [1,0]);
assert(a.ptr != b.ptr);
更改长度或连接时也是如此(鉴于上述情况,我希望如此):
auto a = [1];
auto b = a;
b.length = 2;
a ~= 2;
assert(a == [1,2]);
assert(b == [1,0]);
assert(a.ptr != b.ptr);
但随后切片也出现在画面中,突然变得更加复杂!切片可能是孤立的......
auto a = [1,2,3];
auto b = a;
auto slice = a[1..$]; // [2,3];
slice[0] = 20;
assert(a == [1,20,3]);
assert(a == b);
a.length = 4;
assert(a == [1,20,3,0]);
slice[0] = 200;
assert(b == [1,200,3]); // the reference to b is still valid.
assert(a == [1, 20, 3, 0]); // but the reference to a is now invalid..
b ~= 4;
// Now both references is invalid and the slice is orphan...
// What does the slice modify?
assert(a.ptr != b.ptr);
slice[0] = 2000;
assert(slice == [2000,3]);
assert(a == [1,20,3,0]);
assert(b == [1,200,3,4]);
所以......对同一个动态数组有多个引用是不好的做法吗?并传递切片等?或者我只是在这里,错过了 D 中动态数组的全部要点?