如何将不可变数组存储在存储在 属性 中的变量中 Swift?
How to store immutable arrays in a variable stored property in Swift?
我希望我的 class 有一个可以分配不可变数组的存储 属性。如果我这样做:
class MyClass{
var myItems:[String]
}
我可以为我的 属性 分配不同的数组,但数组是可变的。如果我这样做:
class MyClass{
let myItems:[String]
}
我的数组是不可变的,但我永远无法更改分配给它的内容。有什么办法可以让我的蛋糕不变异吗?
我想出的最好办法是围绕数组创建一个包装器,然后将该类型用于 属性,如下所示:
class MyClass{
struct ImmutableWrapper{
let array:[String]
}
var myItems:ImmutableWrapper
}
…这不是很优雅。
你或许可以试试 NSArray
。数组本身是不可变的,变量可以重新赋值
class MyClass{
var myItems:NSArray
}
这个问题很奇怪,因为你的第一个 myItems
不是各种数组的数组,它只是一个字符串数组。不过,我会尝试以更笼统的方式讨论这个问题。
Swift 不像 Cocoa NSArray 那样区分可变数组和不可变数组。但是你为什么需要这个? Cocoa 需要它,因为 NSArray 是 class,所以如果它是可变的,它可以在 MyClass 的后面改变背部。但是在Swift中,Array是值类型,所以不会发生这种情况。
那么您真正要解决的问题是什么?您应该问问自己,您正试图让外部对象履行什么契约,并尝试将该契约写入 MyClass 的结构中。您的结构数组是一种完全合理的方法。不过,我认为您在这里追求的实际上可能是隐私,而不是不变性。例如,我可能会这样说:
class MyClass{
private var myItemsHidden = [String]()
var myItems:[String] {
get {
return myItemsHidden
}
set {
myItemsHidden = newValue
}
}
}
现在,假设 MyClass 单独存在于它自己的文件中(因为 Swift 中的 private
表示文件私有),myItemsHidden
可以通过 inside MyClass,所以大概 MyClass 知道不要改变任何子数组或您试图阻止的任何内容。它允许自己用 myItemsHidden
.
做什么取决于 MyClass
但是从外部 MyClass,myItemsHidden
不存在;只有 myItems
,任何人唯一能做的就是获取并设置它。 (如果他们得到它并更改它,原件不受影响。他们不能改变原件。)如果您的目的是完全防止任何人在外部设置 myItems
,请删除 setter 函数:
class MyClass{
private var myItemsHidden = [String]()
var myItems:[String] {
get {
return myItemsHidden
}
}
}
现在 myItems
只是一个分发的(出售的)阵列,仅此而已。
如果想法是允许其他 classes 将新数组添加到数组的数组中,您可以添加一个 MyClass 方法来让他们这样做。换句话说,既然这个东西是私有的,就看你你给别人什么样的访问权限了。 MyClass 成为其他 classes 可以用这个值做什么的看门人,因为这个值本身隐藏在 private
墙后面。
我会提出一个比@matt 的优秀答案稍微更简洁的解决方案,它再次利用了访问修饰符。您可以让 Swift 使用 private(set)
:[=,而不是指定一个单独的私有变量,并公开一个仅提供 getter 的 public/internal 计算变量21=]
class MyClass {
private(set) var myItems = [String]()
}
这指定 setter 对当前文件范围是私有的。 getter 保留默认访问级别 (public/internal),因此 classes 外部仍然可以检索 myItems
的副本(副本由于数组是结构,因此按值传递*)。
但是你可能会认为你可以在 myItems
上调用像 append()
这样的变异方法,并在这样做时从 class 之外修改它(毕竟,我们'得到 var myItems
,而不是 let myItems
)。但是 Swift 足够聪明,可以识别出数组在外部应该是不可变的 MyClass
:
let object = MyClass()
object.myItems.append("change me")
// ^ ~~~~~~
// Immutable value of type '[(String)]' only has mutating members named 'append'
因此,这实现了与维护私有 NSMutableArray
的旧 Objective-C 范例非常相似的效果,并公开了一个 public 只读 NSArray
,它在以下情况下创建私有数组的不可变副本叫。不过更优雅,你不觉得吗?
*事实上 Swift 在按值传递方面非常聪明,甚至可能在修改数组之前不会复制数组,甚至可能只跟踪更改(内部)。这意味着您可以分配包含数千个项目的数组,而不会导致大量性能损失。
我希望我的 class 有一个可以分配不可变数组的存储 属性。如果我这样做:
class MyClass{
var myItems:[String]
}
我可以为我的 属性 分配不同的数组,但数组是可变的。如果我这样做:
class MyClass{
let myItems:[String]
}
我的数组是不可变的,但我永远无法更改分配给它的内容。有什么办法可以让我的蛋糕不变异吗?
我想出的最好办法是围绕数组创建一个包装器,然后将该类型用于 属性,如下所示:
class MyClass{
struct ImmutableWrapper{
let array:[String]
}
var myItems:ImmutableWrapper
}
…这不是很优雅。
你或许可以试试 NSArray
。数组本身是不可变的,变量可以重新赋值
class MyClass{
var myItems:NSArray
}
这个问题很奇怪,因为你的第一个 myItems
不是各种数组的数组,它只是一个字符串数组。不过,我会尝试以更笼统的方式讨论这个问题。
Swift 不像 Cocoa NSArray 那样区分可变数组和不可变数组。但是你为什么需要这个? Cocoa 需要它,因为 NSArray 是 class,所以如果它是可变的,它可以在 MyClass 的后面改变背部。但是在Swift中,Array是值类型,所以不会发生这种情况。
那么您真正要解决的问题是什么?您应该问问自己,您正试图让外部对象履行什么契约,并尝试将该契约写入 MyClass 的结构中。您的结构数组是一种完全合理的方法。不过,我认为您在这里追求的实际上可能是隐私,而不是不变性。例如,我可能会这样说:
class MyClass{
private var myItemsHidden = [String]()
var myItems:[String] {
get {
return myItemsHidden
}
set {
myItemsHidden = newValue
}
}
}
现在,假设 MyClass 单独存在于它自己的文件中(因为 Swift 中的 private
表示文件私有),myItemsHidden
可以通过 inside MyClass,所以大概 MyClass 知道不要改变任何子数组或您试图阻止的任何内容。它允许自己用 myItemsHidden
.
但是从外部 MyClass,myItemsHidden
不存在;只有 myItems
,任何人唯一能做的就是获取并设置它。 (如果他们得到它并更改它,原件不受影响。他们不能改变原件。)如果您的目的是完全防止任何人在外部设置 myItems
,请删除 setter 函数:
class MyClass{
private var myItemsHidden = [String]()
var myItems:[String] {
get {
return myItemsHidden
}
}
}
现在 myItems
只是一个分发的(出售的)阵列,仅此而已。
如果想法是允许其他 classes 将新数组添加到数组的数组中,您可以添加一个 MyClass 方法来让他们这样做。换句话说,既然这个东西是私有的,就看你你给别人什么样的访问权限了。 MyClass 成为其他 classes 可以用这个值做什么的看门人,因为这个值本身隐藏在 private
墙后面。
我会提出一个比@matt 的优秀答案稍微更简洁的解决方案,它再次利用了访问修饰符。您可以让 Swift 使用 private(set)
:[=,而不是指定一个单独的私有变量,并公开一个仅提供 getter 的 public/internal 计算变量21=]
class MyClass {
private(set) var myItems = [String]()
}
这指定 setter 对当前文件范围是私有的。 getter 保留默认访问级别 (public/internal),因此 classes 外部仍然可以检索 myItems
的副本(副本由于数组是结构,因此按值传递*)。
但是你可能会认为你可以在 myItems
上调用像 append()
这样的变异方法,并在这样做时从 class 之外修改它(毕竟,我们'得到 var myItems
,而不是 let myItems
)。但是 Swift 足够聪明,可以识别出数组在外部应该是不可变的 MyClass
:
let object = MyClass()
object.myItems.append("change me")
// ^ ~~~~~~
// Immutable value of type '[(String)]' only has mutating members named 'append'
因此,这实现了与维护私有 NSMutableArray
的旧 Objective-C 范例非常相似的效果,并公开了一个 public 只读 NSArray
,它在以下情况下创建私有数组的不可变副本叫。不过更优雅,你不觉得吗?
*事实上 Swift 在按值传递方面非常聪明,甚至可能在修改数组之前不会复制数组,甚至可能只跟踪更改(内部)。这意味着您可以分配包含数千个项目的数组,而不会导致大量性能损失。