假设我有以下协议:
protocol Identifiable {
var id: Int {get}
var name: String {get}
}
而且我有以下结构:
struct A: Identifiable {
var id: Int
var name: String
}
struct B: Identifiable {
var id: Int
var name: String
}
正如你所看到的,我必须“符合”结构A和结构B中的可识别协议 . 但是想象一下,如果我有N个结构需要符合这个协议......我不想'复制/粘贴' '一致性(var id:Int,var name:String)
所以我创建了 protocol extension :
extension Identifiable {
var id: Int {
return 0
}
var name: String {
return "default"
}
}
现在有了这个扩展,我可以创建一个符合Identifiable协议的结构,而不必实现这两个属性:
struct C: Identifiable {
}
现在的问题是我无法为id属性或name属性设置一个值:
var c: C = C()
c.id = 12 // Cannot assign to property: 'id' is a get-only property
发生这种情况是因为在可识别协议中,id和name只能获取 . 现在如果我将id和name属性更改为 ,我会收到以下错误:
类型'C'不符合协议'Identifiable'
发生此错误是因为我没有在协议扩展中实现setter ...所以我更改了协议扩展:
extension Identifiable {
var id: Int {
get {
return 0
}
set {
}
}
var name: String {
get {
return "default"
}
set {
}
}
}
现在错误消失但是如果我为id或name设置了一个新值,它将获得默认值(getter) . 当然, the setter is empty .
我的问题是: What piece of code do I have to put inside the setter? 因为如果我添加self.id = newValue它会崩溃(递归) .
提前致谢 .
3 回答
您似乎想通过协议扩展将
stored property
添加到类型中 . 但是这是不可能的,因为使用扩展名无法添加存储的属性 .我可以向您展示几种选择 .
子类化(面向对象编程)
最简单的方法(可能是你已经想象过的)是使用类而不是结构 .
组件(面向协议的编程)
这种技术在游戏开发中非常流行
现在你可以简单地写你的类型符合
Identifiable
测试
协议和协议扩展非常强大,但它们往往对只读属性和函数最有用 .
对于您要完成的任务(使用默认值存储的属性),类和继承实际上可能是更优雅的解决方案
就像是:
这就是您无法设置属性的原因 .
该属性成为计算属性,这意味着它没有像ObjC那样的后备变量,如_x . 在下面的解决方案代码中,您可以看到xTimesTwo不存储任何内容,而只是计算x的结果 .
请参阅有关计算属性的官方文档 .
您想要的功能也可能是Property Observers .
Setter / getters与Objective-C中的不同 .
你需要的是:
您可以修改setter / getters中的其他属性,这就是它们的用途