我们可以在Swift中编辑 "let" 协议属性的属性吗?
我们可以在Swift中编辑 "let" 协议属性的属性吗?
我有一个类似这样的代码(在一个playground中运行):
protocol ServiceProtocol {
var enabled: Bool { get set }
}
class Service: ServiceProtocol {
var enabled: Bool = false
}
class A {
let service = Service()
}
class B {
let service: ServiceProtocol = Service()
}
let a = A()
let b = B()
a.service.enabled = false
b.service.enabled = false // <-- 错误出现在这里:无法分配给属性:'service' 是一个 'let' 常量
如果我将service
引用为Service
(类A
),一切都按预期工作。但在类B
中,service
是一个ServiceProtocol
,我遇到了错误:
无法分配给属性:'service' 是一个 'let' 常量
对我来说这是荒谬的,因为我并没有尝试给service
分配任何东西:我只是尝试给service
的属性分配一个值。由于enabled
是get set
,我应该能够像在A
中一样进行赋值。
如果我在类B
中将service
声明为var
,错误就消失了。
有什么想法吗?
在Swift中,可以使用类、结构体和枚举来实现协议。由于编译器无法确定实现协议的类型是引用类型还是值类型,因此会出现问题。为了解决这个问题,可以将协议限定为只适用于类,这样代码就能正常工作了。
protocol ServiceProtocol: AnyObject {
var enabled: Bool { get set }
}
现在,下面的代码可以编译通过了:
b.service.enabled = false
非常好,问题解决了!不过,错误信息可能还有改进的空间
我想在这里提醒一下,AnyObject
表示的是Objective-C对象。虽然大多数情况下这不是一个问题,但我认为这是一个重要的知识点。如果想保持它作为一个“仅限于Swift”的对象,可以将协议标记为protocol ServiceProtocol: class {}
。
我个人认为,使用class
而不是AnyObject
会更加清晰地表明协议需要符合的类型必须是类,特别是对于刚接触Swift的人来说。
那是完全错误的。实际上,class
只是AnyObject
的类型别名。你把AnyObject
和NSObject
弄混了。AnyObject
只是一个Swift的协议,所有的类都隐式地符合它,它并不表示Objective-C对象。
只是提一下,“class vs AnyObject protocol”在这里有讨论:stackoverflow.com/q/30176814/1187415(包含了一些指向Swift论坛的链接)。
是的,我认为你需要习惯于编译器的错误信息可能会让人感到困惑或误导:)
令人惊讶的误导,令人惊讶的描述。哇!