为什么 Swift 不允许在类 init 中给 self 赋值,但在协议 init 中却不允许?

Sup*_*tar 5 initialization initializer pass-by-reference pass-by-value swift

我经常发现自己喜欢在structs、enums 和protocols 的初始化器中如何编写类似self = someValue. 当我有一些预定义值或克隆现有值时,这非常有用。

然而,这个语法对 es 不起作用class。我也实在想不通为什么。

无法赋值:“self”是不可变的

如果关注的是双重初始化,Swift 编译器知道我是否、何时以及在何处调用指定superself初始化器,因此它知道我是否已完成初始化该实例。如果担心的是我还没有调用指定的初始化程序,那么应该没问题,因为我只是让这个实例成为对另一个实例的引用(2 vars 1 指针)。如果担心的是并发访问可能导致self已经被初始化...那么这是无意义的,因为我们在初始化器中,而Swift 初始化器不易受此影响

毕竟我发现我可以通过一次性协议来解决这个问题:

class MyClass {
    let content: String
    
    init(content: String) {
        self.content = content
    }

    convenience init(from1 other: MyClass) {
        self = other // Cannot assign to value: 'self' is immutable
    }
}



protocol MyProto {}

extension MyClass: MyProto {}



extension MyProto {
    
    init(from2 other: Self) {
        self = other
    }
}



let foo = MyClass(content: "Foo")

print(MyClass(from1: foo)) // Never would've compiled in the first place
print(MyClass(from2: foo)) // Perfectly OK!
Run Code Online (Sandbox Code Playgroud)

那么为什么这在普通用法中被拒绝,但在协议扩展中被允许呢?

Sul*_*han 3

看来目前的表现符合预期。

\n\n

整个问题已经在 swift 论坛上讨论过:Assigning to Self in Protocol Extensions

\n\n
\n

上次在内部讨论中出​​现这个怪癖时,我们中的一些人的想法是,完全禁止类遵守具有变异要求的协议可能是值得的。如果您考虑一下,这有一定道理 \xe2\x80\x94 似乎很难编写可以对可变值和可变引用进行操作的代码,因为后者没有值语义:

\n\n
var x = y\nx.mutatingProtocolRequirement()\n// did y change too?\n
Run Code Online (Sandbox Code Playgroud)\n\n

然而讨论却以失败告终。

\n
\n