swift - 禁止直接赋值的可变属性 - Swift

标签 swift assignment-operator value-type mutability mutating-function

排除赋值中的变量可变性

swift 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 并在 Foo 中创建并制作 incrementCounter() 函数 增加它,我希望能够直接通过 counter 变量访问变异方法,因为它会使类困惑,并且对于具有许多变异方法的类型来说很烦人。同样,我知道我也可以将 counter 设为常量并将 Counter 设为类,但我需要属性的值类型语义。

最佳答案

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

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

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

这不是我真正想说的,原因和你一样。 Mover 需要是可变的并且是一个结构。因此,理论上可以在这个 Mover 之上将另一个 Mover 分配给我的 state。我只需要与自己订立契约(Contract),不这样做,可惜,这并不容易执行。

如果您真正想要做的只是防止替换具有不同间隔的计数器,您可以使用 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....
}

关于swift - 禁止直接赋值的可变属性 - Swift,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56301299/

相关文章:

ios - 如何在以编程方式创建的按钮上添加 Spinner Indicator

swift - 使用生成的 SDK 处理 AWS API Gateway 错误 (Swift)

c++ - 将 json-Container 复制分配给 vector

c++ - 隐式赋值运算符

c# - C# 中 ObjectIDGenerator 方法的值类型

c# - 在 C# 中对值类型使用 "Equals"似乎不是一个好主意,是吗?

iOS - 打开另一个应用程序警报 - 使用 Dropbox 的示例

macos - Swift NSTableView、NSFileManager,试图将文件名加载到 TableView 中,但选项有问题

gcc - 赋值 : still not implemented in GCC? 中的 C++17 排序

.net - 如何区分一个类型是 ValueType 还是 RefereceType?