我刚刚了解到,变异函数只是第一个参数为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”,为什么?
ios - Swift中的didSet对突变func具有怪异的链式作用-LMLPHP

最佳答案

值得一提的有趣的一点是,在将 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/

10-12 14:45