如何在Swift中创建不可变数组?

时间:2022-09-18 22:00:27

How do I create an immutable array in Swift?

如何在Swift中创建不可变数组?

A superficial reading of the docs would suggest you can just do

对这些文档的肤浅解读表明你可以这么做

let myArray = [1,2,3]

But sadly this actually produces a mutable, fixed-size array. This mutability creates the usual puzzles with unsuspected aliasing and functions mutating their arguments:

但遗憾的是,这实际上生成了一个可变的、固定大小的数组。这种易变性产生了常见的谜题,它们具有不可怀疑的混叠性,并具有改变其参数的功能:

let outterArray = [myArray, myArray]
outterArray[0][0] = 2000
outterArray //=> [[2000,2,3],[2000,2,3]]   surprise!

func notReallyPure(arr:Int[]) -> () { arr[0] = 3000 }
notReallyPure(myArray)
myArray // => [3000,2,3]

Not much better than C.

不比C好多少。

If I want immutability, is the best option really to wrap it in an NSArray like so:

如果我想要不变性,最好的办法是把它用NSArray的方式来包装:

let immutableArray = NSArray(myArray: [1,2,3])

That seems nuts. What am I missing here?

这似乎是疯了。我错过了什么?

UPDATE (2015-07-26):

更新(2015-07-26):

This question dates from the very early days of Swift. Swift has since then been updated so that immutable arrays are actually immutable, as answers below indicate.

这个问题可以追溯到斯威夫特早期。从那以后,Swift就被更新了,因此不可变的数组实际上是不可变的,如下面的答案所示。

5 个解决方案

#1


27  

This has changed with Xcode 6 beta 3. While arrays used to be semi-mutable, as you describe, with their elements changeable but their length fixed, now immutable arrays share the same value semantics as Dictionaries:

Xcode 6 beta 3改变了这一点。正如您所描述的,数组过去是半可变的,其元素可以更改,但其长度是固定的,而现在不可变数组与字典共享相同的值语义:

From the Xcode 6 beta 3 release notes:

从Xcode 6 beta 3发行说明:

• Array in Swift has been completely redesigned to have full value semantics like Dictionary and String have always had in Swift. This resolves various mutability problems – now a 'let' array is completely immutable, and a 'var' array is completely mutable – composes properly with Dictionary and String, and solves other deeper problems. Value semantics may be surprising if you are used to NSArray or C arrays: a copy of the array now produces a full and independent copy of all of the elements using an efficient lazy copy implementation. This is a major change for Array, and there are still some performance issues to be addressed. Please !see the Swift Programming Language for more information. (17192555)

•Swift中的数组已经完全重新设计,以具有完整的值语义,就像Dictionary和String在Swift中一直具有的那样。这解决了各种可变性问题——现在“让”数组是完全不可变的,而“var”数组是完全可变的——与Dictionary和String正确组合,并解决了其他更深层次的问题。如果您已经习惯了NSArray或C数组,那么值语义可能会令人惊讶:该数组的副本现在使用高效的延迟复制实现生成所有元素的完整和独立的副本。这是数组的一个主要更改,还有一些性能问题需要处理。有关更多信息,请参阅Swift编程语言。(17192555)

The original information on arrays in the Swift book was updated on 7th July 2014 to reflect the beta 3 changes. (If you're using iBooks on a Mac, as I was, you may need to delete and re-download it to pick up the 7th July update—I couldn't get the thing to update automatically.)

Swift book中有关数组的原始信息在2014年7月7日更新,以反映beta 3的变化。(如果你像我一样在Mac电脑上使用iBooks,你可能需要删除并重新下载它以获取7月7日的更新——我无法让它自动更新。)

#2


8  

Seems to be a bug and to be fixed soon.

似乎是一个bug,很快就会被修复。

Cited from Apple dev forum:

来自苹果开发论坛:

Question:

问题:

Inconsistency with let for Array and Dictionary

与let的数组和字典不一致

Final answer:

最后的答案:

This is considered to be a bug, not a feature, and will be fixed in a later Beta.
-Chris

这被认为是一个bug,而不是一个特性,并将在稍后的测试中修复。屁股的

#3


1  

There is not a great answer for this, and it is bizarre.

对此没有一个很好的答案,而且很奇怪。

You can, however, prevent accidental mutation of arrays as they flow through your program by calling yourArray.unshare(). This causes the array to be copied when it's assigned to a new variable.

但是,您可以通过调用yourArray.unshare()来防止阵列的意外突变。当数组被分配给一个新变量时,这会导致数组被复制。

#4


1  

It is now possible.

现在是可能的。

From Apple Developer

从苹果开发者

If you assign an array or a dictionary to a constant, that array or dictionary is immutable, and its size and contents cannot be changed.

如果将数组或字典分配给常量,则该数组或字典是不可变的,其大小和内容不能更改。

So now

所以现在

let myArray = [1,2,3]

produces completely immutable array. Yay!

产生完全不变的数组。耶!

#5


0  

IMHO the simplest workaround is simply wrap it in the closure as follows:

我认为最简单的解决方法就是简单地将它封装在如下的闭包中:

let mutableElements =  [0,1,2,3]
let reallyImmutable = {[0,1,2,3]}
println(mutableElements)
for i in 0..mutableElements.count { mutableElements[i] *= -1 }
println(mutableElements)    // [0, -1, -2, -3]
println(reallyImmutable())
for i in 0..reallyImmutable().count { reallyImmutable()[i] *= -1 }
println(reallyImmutable())      // [0, 1, 2, 3]
println(reallyImmutable()[2])   // 2
let anotherImmutable = { reallyImmutable().map{ $0 * $0 } }
println(anotherImmutable())     // [0, 1, 4, 9]

You pay extra {} on declaration and () for each access but that also makes your code speak for itself.

您需要为每个访问支付额外的{}声明和(),但这也使得您的代码可以自己发言。

Dan the Mutable Programmer

丹可变的程序员

P.S. Wrote a wrapper class ImmutableArray.

P.S.写了一个包装类ImmutableArray。

#1


27  

This has changed with Xcode 6 beta 3. While arrays used to be semi-mutable, as you describe, with their elements changeable but their length fixed, now immutable arrays share the same value semantics as Dictionaries:

Xcode 6 beta 3改变了这一点。正如您所描述的,数组过去是半可变的,其元素可以更改,但其长度是固定的,而现在不可变数组与字典共享相同的值语义:

From the Xcode 6 beta 3 release notes:

从Xcode 6 beta 3发行说明:

• Array in Swift has been completely redesigned to have full value semantics like Dictionary and String have always had in Swift. This resolves various mutability problems – now a 'let' array is completely immutable, and a 'var' array is completely mutable – composes properly with Dictionary and String, and solves other deeper problems. Value semantics may be surprising if you are used to NSArray or C arrays: a copy of the array now produces a full and independent copy of all of the elements using an efficient lazy copy implementation. This is a major change for Array, and there are still some performance issues to be addressed. Please !see the Swift Programming Language for more information. (17192555)

•Swift中的数组已经完全重新设计,以具有完整的值语义,就像Dictionary和String在Swift中一直具有的那样。这解决了各种可变性问题——现在“让”数组是完全不可变的,而“var”数组是完全可变的——与Dictionary和String正确组合,并解决了其他更深层次的问题。如果您已经习惯了NSArray或C数组,那么值语义可能会令人惊讶:该数组的副本现在使用高效的延迟复制实现生成所有元素的完整和独立的副本。这是数组的一个主要更改,还有一些性能问题需要处理。有关更多信息,请参阅Swift编程语言。(17192555)

The original information on arrays in the Swift book was updated on 7th July 2014 to reflect the beta 3 changes. (If you're using iBooks on a Mac, as I was, you may need to delete and re-download it to pick up the 7th July update—I couldn't get the thing to update automatically.)

Swift book中有关数组的原始信息在2014年7月7日更新,以反映beta 3的变化。(如果你像我一样在Mac电脑上使用iBooks,你可能需要删除并重新下载它以获取7月7日的更新——我无法让它自动更新。)

#2


8  

Seems to be a bug and to be fixed soon.

似乎是一个bug,很快就会被修复。

Cited from Apple dev forum:

来自苹果开发论坛:

Question:

问题:

Inconsistency with let for Array and Dictionary

与let的数组和字典不一致

Final answer:

最后的答案:

This is considered to be a bug, not a feature, and will be fixed in a later Beta.
-Chris

这被认为是一个bug,而不是一个特性,并将在稍后的测试中修复。屁股的

#3


1  

There is not a great answer for this, and it is bizarre.

对此没有一个很好的答案,而且很奇怪。

You can, however, prevent accidental mutation of arrays as they flow through your program by calling yourArray.unshare(). This causes the array to be copied when it's assigned to a new variable.

但是,您可以通过调用yourArray.unshare()来防止阵列的意外突变。当数组被分配给一个新变量时,这会导致数组被复制。

#4


1  

It is now possible.

现在是可能的。

From Apple Developer

从苹果开发者

If you assign an array or a dictionary to a constant, that array or dictionary is immutable, and its size and contents cannot be changed.

如果将数组或字典分配给常量,则该数组或字典是不可变的,其大小和内容不能更改。

So now

所以现在

let myArray = [1,2,3]

produces completely immutable array. Yay!

产生完全不变的数组。耶!

#5


0  

IMHO the simplest workaround is simply wrap it in the closure as follows:

我认为最简单的解决方法就是简单地将它封装在如下的闭包中:

let mutableElements =  [0,1,2,3]
let reallyImmutable = {[0,1,2,3]}
println(mutableElements)
for i in 0..mutableElements.count { mutableElements[i] *= -1 }
println(mutableElements)    // [0, -1, -2, -3]
println(reallyImmutable())
for i in 0..reallyImmutable().count { reallyImmutable()[i] *= -1 }
println(reallyImmutable())      // [0, 1, 2, 3]
println(reallyImmutable()[2])   // 2
let anotherImmutable = { reallyImmutable().map{ $0 * $0 } }
println(anotherImmutable())     // [0, 1, 4, 9]

You pay extra {} on declaration and () for each access but that also makes your code speak for itself.

您需要为每个访问支付额外的{}声明和(),但这也使得您的代码可以自己发言。

Dan the Mutable Programmer

丹可变的程序员

P.S. Wrote a wrapper class ImmutableArray.

P.S.写了一个包装类ImmutableArray。