问题描述
我很好奇为什么这不起作用:
I am curious why this doesn't work:
public protocol MyProtocol {
var i: Int { get set }
}
public protocol MyProtocol2: class, MyProtocol {}
public extension MyProtocol2 where Self: AnyObject {
func a() {
i = 0 <-- error
}
}
错误:
无法分配给属性:'self'是不可变的
为什么?只有类可以采用 MyProtocol2.如果我在 MyProtocol 后面添加 : class
声明,它会起作用.我不明白为什么它不适用于子协议.
Why? Only classes can adopt MyProtocol2. If I add : class
declaration behind MyProtocol it works. I do not understand why it doesn't work on a subprotocol.
推荐答案
您的示例无法编译,因为 MyProtocol
不是类绑定的,因此可以具有 mutating代码> 要求和扩展成员.这包括属性设置器,默认情况下它们是
mutating
.这些成员可以自由地为 self
重新分配一个全新的值,这意味着编译器需要确保在可变变量上调用它们.
Your example doesn't compile because MyProtocol
isn't class-bound, and as such can have mutating
requirements and extension members. This includes property setters, which are by default mutating
. Such members are free to re-assign a completely new value to self
, meaning that the compiler needs to ensure they're called on mutable variables.
例如,考虑:
public protocol MyProtocol {
init()
var i: Int { get set } // implicitly `{ get mutating set }`
}
extension MyProtocol {
var i: Int {
get { return 0 }
// implicitly `mutating set`
set { self = type(of: self).init() } // assign a completely new instance to `self`.
}
}
public protocol MyProtocol2 : class, MyProtocol {}
public extension MyProtocol2 where Self : AnyObject {
func a() {
i = 0 // error: Cannot assign to property: 'self' is immutable
}
}
final class C : MyProtocol2 {
init() {}
}
let c = C()
c.a()
如果这是合法的,调用c.a()
会将一个全新的C
实例重新分配给变量c
.但是 c
是不可变的,因此代码的格式不是很好.
If this were legal, calling c.a()
would re-assign a completely new instance of C
to the variable c
. But c
is immutable, therefore the code is not well formed.
使 MyProtocol
类绑定(即 protocol MyProtocol : AnyObject
或弃用的拼写 protocol MyProtocol : class
)有效,因为现在编译器知道只有类可以符合 MyProtocol
.因此,它通过禁止 mutating
要求和扩展成员来强加引用语义,从而防止 self
的任何变化.
Making MyProtocol
class bound (i.e protocol MyProtocol : AnyObject
or the deprecated spelling protocol MyProtocol : class
) works because now the compiler knows that only classes can conform to MyProtocol
. Therefore it imposes reference semantics by forbidding mutating
requirements and extension members and therefore prevents any mutations of self
.
您可以使用的另一种选择是将需求 i
的 setter 标记为 nonmutating
- 因此这意味着它只能由非变异 setter 来满足.这使您的代码再次格式良好:
Another option at your disposal is to mark the setter for the requirement i
as being nonmutating
– therefore meaning that it can only be satisfied by a non-mutating setter. This makes your code once again well-formed:
public protocol MyProtocol {
init()
var i: Int { get nonmutating set }
}
public protocol MyProtocol2 : class, MyProtocol {}
public extension MyProtocol2 where Self : AnyObject {
func a() {
i = 0 // legal
}
}
这篇关于为什么我不能在 self 是一个类的协议扩展中更改变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!