代码如下:
protocol A {
var a: Int { get set }
}
extension A {
var convenientAccessor: Int {
get { return a }
set { a = newValue }
}
}
class B: A {
var a: Int = 0
}
func acceptsB (instance: B) {
instance.a = 1 // This compiles
instance.convenientAccessor = 2 // This does not
}
我有点理解这里的问题,但我真的很想得到更深入理解它的人的回答,更重要的是我的问题的解决方法,即我想传递已知的类类型并能够使用方便的访问器,而不会被我使用值类型的可能性所抑制。在我的例子中,定义这些方便的访问器的协议(protocol)不应该是类绑定(bind)的(它们对于值类型是完全有效和有用的),所以虽然这在技术上是一种解决方法,但我并不满意。
最佳答案
让我们从一个总结开始:convenientAccessor
是一个可写属性,因此对它的任何赋值都会导致突变。这种突变发生在您的函数内部。
问题在于,当使用 convenientAccessor
属性时,编译器将 instance
视为协议(protocol) A
,并且因为函数的参数是 let
,它不允许对它们进行修改,因为此时协议(protocol)也可以通过值类型实现。
我想到的两个解决方案是:
将协议(protocol)
A
限制为仅类:protocol A: class
这会通知编译器只有类才能符合协议(protocol),这允许对任何类型的变量(
<let
或var
)进行修改使函数参数
inout
:func acceptsB (instance: inout B)
这会创建一个“写入漏洞”,因为现在
instance
是可写的,所以对它的任何更改都会传播回上游,即使B
是一个值类型。
就个人而言,如果您计划只使用类,我会选择 #1,正如您在问题中提到的那样。
关于swift - 在非类绑定(bind)协议(protocol)的扩展中,实例必须被视为值类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52417947/