Swift: 无法为协议的 属性 赋值?

Swift: Failed to assign value to a property of protocol?

Class A 提供了一个字符串值。 Class B 内部有两个 A 类型的成员,并提供一个计算 属性 "v" 来选择其中一个。

class A {
    var value: String

    init(value: String) {
        self.value = value
    }
}

class B {
    var v1: A?
    var v2: A = A(value: "2")

    private var v: A {
        return v1 ?? v2
    }

    var value: String {
        get {
            return v.value
        }
        set {
            v.value = newValue
        }
    }
}

这段代码很简单而且有效。由于 A 和 B 都有一个成员 "value",我将其作为这样的协议:

protocol ValueProvider {
    var value: String {get set}
}

class A: ValueProvider {
    var value: String

    init(value: String) {
        self.value = value
    }
}

class B: ValueProvider {
    var v1: ValueProvider?
    var v2: ValueProvider = A(value: "2")

    private var v: ValueProvider {
        return v1 ?? v2
    }

    var value: String {
        get {
            return v.value
        }
        set {
            v.value = newValue // Error: Cannot assign to the result of the expression
        }
    }
}

如果我更改以下代码

v.value = newValue

var v = self.v
v.value = newValue

又能用了!

这是 Swift 的错误,还是 属性 协议的特殊问题?

您必须将协议定义为 class 协议:

protocol ValueProvider : class {
    var value: String {get set}
}

然后

var value: String {
    get { return v.value }
    set { v.value = newValue }
}

按预期编译和工作(即将新值分配给 v1 引用的对象,如果 v1 != nil,以及对象 否则由 v2 引用。

vValueProvider 类型的只读计算 属性。 通过将协议定义为 class 协议,编译器知道 v 引用类型 ,因此它的 v.value 属性 即使引用本身是常量也可以修改。

您的初始代码示例有效,因为 v 属性 有 类型 A 是引用类型。

你的解决方法

set {
    var tmp = v1 ?? v2
    tmp.value = newValue
}

之所以有效,是因为 变量 的(读写)属性可以设置在 任何大小写(值类型或引用类型)。