0

排除赋值中的可变可变性

斯威夫特 5.0 - Xcode 10.2.1

我有一个带有我希望可变的属性的类,除了我不想让该属性直接分配给=运算符。举个例子:

class Foo {
    var counter = Counter()

    init() { }
}

struct Counter {
    private(set) var n = 0

    let interval: Int

    mutating func increment() {
        n += interval
    }

    init(by interval: Int = 1) {
        self.interval = interval
    }
}

我想被允许的:

let foo = Foo()
foo.counter.increment()

我不想被允许的:

let fasterCounter = Counter(by: 10)
let foo = Foo()
foo.counter = fasterCounter

注意: 虽然我知道我可以创建counter一个private(set) var并创建一个incrementCounter()函数Foo来增加它,但我希望能够直接通过counter变量访问变异方法,因为它会使类变得混乱,并且对于类型来说很烦人许多变异方法。同样,我知道我也可以创建counter一个常量和Counter一个类,但我需要属性的值类型语义。

4

1 回答 1

1

您已正确列出所有可用选项。如果这就是您要问的,那么您没有不知道的其他技巧。这只是 Swift 的一个缺点,当(经常发生)你想使用辅助结构时。

我在自己的代码中一直遇到这个问题。例如:

final class ViewController: UIViewController {
    lazy var state = Mover(owner:self)

这不是我真正想说的,原因和你一样。Mover 需要是可变的并且是一个结构。所以理论上另一个 Mover 可以分配给我state在这个之上。我只需要与自己签订一份合同,不要那样做,唉,这并不容易执行。

如果您真正想要做的只是防止替换具有不同间隔的计数器,您可以使用didSet观察者(当然强制执行是在运行时,而不是编译时):

var counter = Counter() {
    didSet {
        if oldValue.interval != counter.interval {
            fatalError("hey")
        }
    }
}

但是你可以想象这会变得非常复杂。每个突变替换一个不同的计数器,因此确保这种替换“只是”突变结果的预防措施可能必须非常复杂。此外,如果您打算采用这种方法,您可能希望让 Counter 自己知道什么是“合法”突变。在这个简单的例子中,我们也许可以使用相等:

class Foo {
    var counter = Counter() {
        didSet {
            if oldValue != counter {
                fatalError("hey")
            }
        }
    }
    init() { }
}

struct Counter : Equatable {
    static func ==(lhs:Counter,rhs:Counter) -> Bool {
        return rhs.interval == lhs.interval
    }
    // the rest as before....
}
于 2019-05-25T03:20:59.260 回答