简体   繁体   English

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

[英]How do you create an immutable array in Swift?

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已经更新,因此不可变数组实际上是不可变的,如下面的答案所示。

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.虽然数组过去是半可变的,正如你所描述的那样,它们的元素可以更改但是它们的长度是固定的,现在不可变数组与Dictionaries共享相同的值语义:

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. •Swift中的数组已经完全重新设计,具有完全值语义,如Dictionary和String在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. 这解决了各种可变性问题 - 现在'let'数组是完全不可变的,'var'数组是完全可变的 - 用Dictionary和String正确组合,并解决其他更深层次的问题。 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. 如果您习惯使用NSArray或C数组,则值语义可能会令人惊讶:数组的副本现在使用有效的延迟复制实现生成所有元素的完整且独立的副本。 This is a major change for Array, and there are still some performance issues to be addressed. 这是Array的一个重大变化,仍有一些性能问题需要解决。 Please !see the Swift Programming Language for more information. 请参阅Swift编程语言以获取更多信息。 (17192555) (17192555)

The original information on arrays in the Swift book was updated on 7th July 2014 to reflect the beta 3 changes. Swift中有关阵列的原始信息已于2014年7月7日更新,以反映beta 3的变化。 (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.) (如果您在Mac上使用iBooks,就像我一样,您可能需要删除并重新下载它以获取7月7日的更新 - 我无法自动更新。)

Seems to be a bug and to be fixed soon. 似乎是一个错误,很快就会修复。

Cited from Apple dev forum : 引自Apple dev论坛

Question: 题:

Inconsistency with let for Array and Dictionary 与let for Array和Dictionary不一致

Final answer: 最终答案:

This is considered to be a bug, not a feature, and will be fixed in a later Beta. 这被认为是一个错误,而不是一个功能,并将在以后的Beta中修复。
-Chris -克里斯

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() . 但是,您可以通过调用yourArray.unshare()防止数组在流经程序时意外突变。 This causes the array to be copied when it's assigned to a new variable. 这会导致在将数组分配给新变量时复制该数组。

It is now possible. 现在可以了。

From Apple Developer 来自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! 好极了!

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 Dan the Mutable Programmer

PS Wrote a wrapper class ImmutableArray . PS写了一个包装类ImmutableArray

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM