我目前对协议中的可获取属性有些困惑。考虑这个例子:
protocol Person {
var name: String { get }
}
我希望name
属性为只读,但是我发现您可以更改该值而不会引起编译器投诉:
struct Driver: Person {
var name: String
}
var driver = Driver(name: "Ryan")
driver.name = "Changed!"
如果使用driver
关键字定义let
,则编译器会引发错误,但如果我理解正确,则与协议无关,因为常量结构在Swift中是不变的。
方法交互的行为符合我的预期:
extension Person {
mutating func changeName(_ newName: String) {
self.name = newName // Error: 'name' is a get-only property
}
}
我是Swift的新手,提到的细微差别可能没有任何实际用途,但是这种行为使我问自己是否对结构的工作原理缺乏基本的了解。
协议要求是
可以读取的变量
name
这并不意味着采用此协议的结构中的变量必须是只读的。
在代码中,您直接以Driver
类型更改变量,不涉及协议。
另一方面,如果您注释协议类型,则会出现预期的错误
var driver : Person = Driver(name: "Ryan")
driver.name = "Changed!" // Cannot assign to property: 'name' is a get-only property
协议仅声明必需的接口,而没有声明符合类型的完整接口。您的符合类型可以添加协议不需要的其他属性/方法。
吸气剂和塞脂剂也是如此。如果协议属性要求为get
,则表示一致类型必须具有属性的吸气剂,但这并不意味着它也不能具有setter
。
但是,同样的方法在其他方面是行不通的。如果协议将某个属性声明为{ get set }
,则该属性必须具有设置器(可变)。
苹果documentation很好地解释了这一点。
可以通过多种方式通过符合类型来满足吸气剂和设置剂的要求。如果属性声明同时包含get和set关键字,则符合类型可以使用存储变量属性或既可读又可写的计算属性(即,同时实现getter和setter的)来实现它。但是,该属性声明不能实现为常量属性或只读的计算属性。如果属性声明仅包含get关键字,则可以将其实现为任何类型的属性。