5

A 类提供一个字符串值。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 都有一个成员“值”,因此我将其设为这样的协议:

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 的错误,还是协议属性的特殊情况?

4

1 回答 1

11

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

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

然后

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

编译并按预期工作(即,将新值分配给v1if引用的对象v1 != nil,以及 else 引用的对象v2)。

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

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

和你的解决方法

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

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

于 2015-04-19T11:10:49.347 回答