为什么我不能在self是类的协议扩展中更改变量?

时间:2018-08-03 19:05:42

标签: swift protocols

我很好奇为什么这行不通:

.btn-update {
    color:#004990;
    background-color: #F58020;
}

.btn-update:hover {
    background-color: #F8AA69;
    color: #3E5485
}

.btn-delete {
    color:#F58020;
    background-color:#004990;
}

.btn-delete:hover {
    background-color: #3E5485;
    color: #F8AA69;
}

.test{
    color: #FF0000;
}

错误:

  

无法分配给属性:“自身”是不可变的

为什么?只有类可以采用MyProtocol2。如果我在MyProtocol后面添加public protocol MyProtocol { var i: Int { get set } } public protocol MyProtocol2: class, MyProtocol {} public extension MyProtocol2 where Self: AnyObject { func a() { i = 0 <-- error } } 声明,它将起作用。我不明白为什么它在子协议上不起作用。

2 个答案:

答案 0 :(得分:9)

您的示例无法编译,因为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
  }
}

答案 1 :(得分:0)

属性设置器会在被调用方上触发突变,这意味着对属性进行操作的任何方法都必须声明为mutating

public extension MyProtocol2 where Self: AnyObject {
    mutating func a() {
        i = 0
    }
}

这将允许在方法中对self进行任何写操作。