swift - 为什么我不能在 self 是一个类的协议扩展中更改变量?
问题描述
我很好奇为什么这不起作用:
public protocol MyProtocol {
var i: Int { get set }
}
public protocol MyProtocol2: class, MyProtocol {}
public extension MyProtocol2 where Self: AnyObject {
func a() {
i = 0 <-- error
}
}
错误:
无法分配给属性:“自我”是不可变的
为什么?只有类可以采用 MyProtocol2。如果我: class
在 MyProtocol 后面添加声明,它就可以工作。我不明白为什么它不适用于子协议。
解决方案
您的示例无法编译,因为MyProtocol
它不是类绑定的,因此可以具有mutating
要求和扩展成员。这包括属性设置器,默认情况下是mutating
. 这些成员可以自由地为 重新分配一个全新的值self
,这意味着编译器需要确保在可变变量上调用它们。
例如,考虑:
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
是不可变的,因此代码格式不正确。
使MyProtocol
类绑定(即protocol MyProtocol : AnyObject
或不推荐的拼写protocol MyProtocol : class
)有效,因为现在编译器知道只有类可以符合MyProtocol
。因此,它通过禁止mutating
需求和扩展成员来强加引用语义,从而防止self
.
您可以使用的另一个选项是将需求的设置器标记i
为存在nonmutating
- 因此这意味着它只能由非变异设置器来满足。这使您的代码再次格式良好:
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
}
}
推荐阅读
- python - 索引位置未知时切片与索引之间的区别
- android - 为什么okhttp的Post方法出现错误[不支持HTTP请求中指定的Content-Type标头:application/x-www-form-urlencoded]?
- wordpress - ACF Group 字段不显示在前端
- python - Python - 检查单词“Is Isogram”是否
- javascript - Firebase:doc.data() 返回空对象
- ios - 在swift中使用Timer更改标签时防止UIButton标签不闪烁
- sql - 选择上方或下方附加行的结果
- java - 在我的 java 函数中实现搜索
- php - php查询函数重复数据
- build - Netlify - 我的构建可执行文件的权限被拒绝