禁止直接赋值的可变 属性 - Swift
Mutable Property that Prohibits Direct Assignment - Swift
排除赋值中的变量可变性
Swift 5.0 - Xcode 10.2.1
我有一个 class 和一个 属性 我想可变,除此之外我不想让 属性 直接分配给=
运算符。举个例子:
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
变量的方法,因为它使 class 混乱,并且对于具有许多变异方法的类型来说很烦人。同样,我知道我也可以使 counter
成为常量,而 Counter
成为 class,但我需要 属性.
的值类型语义
您已正确列出所有可用选项。如果您要问的话,没有您不知道的其他技巧。这只是 Swift 的一个缺点,当(经常发生)您想使用辅助结构时。
我在自己的代码中一直遇到这个问题。例如:
final class ViewController: UIViewController {
lazy var state = Mover(owner:self)
这不是我真正想说的,原因和你一样。 Mover 需要是可变的并且是一个结构。因此,理论上可以在这个 Mover 之上为我的 state
分配另一个 Mover。我只需要与自己订立合同不这样做,唉,这不容易执行。
如果您真正想要做的只是防止替换具有不同间隔的计数器,您可以使用 didSet
观察器(当然强制执行是在运行时,而不是编译时):
var counter = Counter() {
didSet {
if oldValue.interval != counter.interval {
fatalError("hey")
}
}
}
但是你可以想象这会变得非常复杂。每个突变都会替换一个不同的计数器,因此确保此替换是 "just" 突变结果的预防措施可能必须非常详尽。此外,如果您打算采用这种方法,您可能希望将了解什么构成 "legal" 突变的工作强加给 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 5.0 - Xcode 10.2.1
我有一个 class 和一个 属性 我想可变,除此之外我不想让 属性 直接分配给=
运算符。举个例子:
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
变量的方法,因为它使 class 混乱,并且对于具有许多变异方法的类型来说很烦人。同样,我知道我也可以使 counter
成为常量,而 Counter
成为 class,但我需要 属性.
您已正确列出所有可用选项。如果您要问的话,没有您不知道的其他技巧。这只是 Swift 的一个缺点,当(经常发生)您想使用辅助结构时。
我在自己的代码中一直遇到这个问题。例如:
final class ViewController: UIViewController {
lazy var state = Mover(owner:self)
这不是我真正想说的,原因和你一样。 Mover 需要是可变的并且是一个结构。因此,理论上可以在这个 Mover 之上为我的 state
分配另一个 Mover。我只需要与自己订立合同不这样做,唉,这不容易执行。
如果您真正想要做的只是防止替换具有不同间隔的计数器,您可以使用 didSet
观察器(当然强制执行是在运行时,而不是编译时):
var counter = Counter() {
didSet {
if oldValue.interval != counter.interval {
fatalError("hey")
}
}
}
但是你可以想象这会变得非常复杂。每个突变都会替换一个不同的计数器,因此确保此替换是 "just" 突变结果的预防措施可能必须非常详尽。此外,如果您打算采用这种方法,您可能希望将了解什么构成 "legal" 突变的工作强加给 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....
}