我正在阅读文档,我经常对语言的一些设计决策摇头。但真正让我困惑的是数组是如何处理的。

我冲到操场上试了试。你也可以试试。第一个例子:

var a = [1, 2, 3]
var b = a
a[1] = 42
a
b

这里a和b都是[1,42,3],我可以接受。数组被引用-好的!

现在来看这个例子:

var c = [1, 2, 3]
var d = c
c.append(42)
c
d

c是[1,2,3,42]但d是[1,2,3]。也就是说,d在上一个例子中看到了变化,但在这个例子中没有看到。文档上说这是因为长度变了。

现在,看看这个:

var e = [1, 2, 3]
var f = e
e[0..2] = [4, 5]
e
f

E是[4,5,3],很酷。有一个多索引替换是很好的,但是f STILL没有看到变化,即使长度没有改变。

总而言之,如果更改了一个元素,对数组的常见引用就会看到变化,但如果更改了多个元素或附加项,则会生成一个副本。

在我看来,这是一个非常糟糕的设计。我这样想对吗?有什么原因让我不明白数组为什么应该这样做吗?

编辑:数组已经改变,现在有值语义。理智多了!


当前回答

在后来的Swift版本中,数组的行为有什么变化吗?我只是运行你的例子:

var a = [1, 2, 3]
var b = a
a[1] = 42
a
b

结果是[1,42,3]和[1,2,3]

其他回答

为此我使用.copy()。

    var a = [1, 2, 3]
    var b = a.copy()
     a[1] = 42 

来自Swift语言的官方文档:

请注意,使用下标语法设置新值时不会复制数组,因为使用下标语法设置单个值不会改变数组的长度。但是,如果将新项附加到数组,则会修改数组的长度。这会提示Swift在你附加新值的时候创建一个新的数组副本。因此,a是数组.....的一个单独的独立副本

阅读本文档中数组的赋值和复制行为的整个部分。您将发现,当您替换数组中的一组项时,数组将为所有项获取自身的副本。

这种行为在Xcode 6 beta 3中有所改变。数组不再是引用类型,而是采用写时复制机制,这意味着只要从一个或另一个变量中更改数组的内容,数组就会被复制,而且只会更改一个副本。


旧的回答:

正如其他人指出的那样,Swift尽量避免复制数组,包括在一次更改单个索引的值时。

如果你想确保一个数组变量(!)是唯一的,即不与另一个变量共享,你可以调用unshare方法。这将复制数组,除非它已经只有一个引用。当然,您也可以调用copy方法,它将始终进行复制,但首选unshare以确保没有其他变量保留同一数组。

var a = [1, 2, 3]
var b = a
b.unshare()
a[1] = 42
a               // [1, 42, 3]
b               // [1, 2, 3]

我发现:当且仅当操作有可能改变数组的长度时,该数组将是引用数组的可变副本。在上一个例子中,f[0..2]如果索引数量很多,操作就有可能改变它的长度(可能是不允许重复的),所以它会被复制。

var e = [1, 2, 3]
var f = e
e[0..2] = [4, 5]
e // 4,5,3
f // 1,2,3


var e1 = [1, 2, 3]
var f1 = e1

e1[0] = 4
e1[1] = 5

e1 //  - 4,5,3
f1 // - 4,5,3

注意,数组的语义和语法在Xcode beta 3版本中发生了改变,所以这个问题不再适用。以下答案适用于beta 2:


这是出于性能考虑。基本上,他们尽量避免复制数组(并声称“类似c的性能”)。引用语言书:

对于数组,只有在执行可能修改数组长度的操作时才会发生复制。这包括追加、插入或删除项,或使用范围下标替换数组中的一段项。

我同意这有点令人困惑,但至少对它的工作原理有一个清晰而简单的描述。

该部分还包括有关如何确保数组被唯一引用、如何强制复制数组以及如何检查两个数组是否共享存储的信息。