我刚刚了解到,变异函数只是第一个参数为inout的 curry 函数,因此下面的代码将起作用,并将firstName
更改为"John"
struct Person {
var firstName = "Matt"
mutating func changeName(fn: String) {
firstName = fn
}
}
var p = Person()
let changer = Person.changeName
changer(&p)("John")
p.firstName
但是,当我像下面那样向
p
添加属性观察器时,发生了奇怪的事情,您可以看到firstName
仍然是“Matt”,为什么?最佳答案
值得一提的有趣的一点是,在将 curry 烤制的二传手称为之前,观察者称为:struct Person {
var firstName = "Matt"
mutating func changeName(fn: String) {
firstName = fn
}
}
var p: Person = Person() {
didSet {
print("p was set")
}
}
print("1: \(p.firstName)")
let changer = Person.changeName
print("2: \(p.firstName)")
let setter = changer(&p)
print("3: \(p.firstName)")
setter("John")
print("4: \(p.firstName)")
p.changeName("John")
print("5: \(p.firstName)")
打印:1: Matt
2: Matt
p was set
3: Matt
4: Matt
p was set
5: John
因此,似乎在inout结构上获取setter方法会执行实际的突变。这是通过inout
参数在语义上的工作方式来解释的:当参数传递给函数时,其值将被复制到函数可以对其进行突变的位置。当函数返回时,该值将被复制回原始位置,从而触发设置查看器一次,无论该值是否更改。
当我们将获取预先填写好的 curry 二传手的方式更改为:let setter = p.changeName
...编译器对象:error: partial application of 'mutating' method is not allowed
似乎编译器理解关闭inout值是一个坏主意,因为它基本上是在引用值类型。
闭包可以让您随时更改结构的值,即使编译器认为它是恒定的也是如此。为了避免这种不幸的情况,编译器只是禁止在inout上关闭。
您发现了一个使编译器傻瓜并解决诊断问题的情况。这似乎是一个错误,应该提出。
简化版:struct Foo {
mutating func foo() {}
}
var f = Foo()
let m = Foo.foo
let s = m(&f)
最后两行之一应发出错误,类似于let x = f.foo
。
关于ios - Swift中的didSet对突变func具有怪异的链式作用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35555601/