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