如何从转义闭包中更改 inout 参数?

How can I change an inout parameter from within a escaping closure?

我试图从转义闭包中修改函数参数,如下所示:

var completion = [()->Void]()

func addCompletion(closure: @escaping ()->Void) {
    completion.append(closure)
}

func testAdd(v: inout Int) {
    addCompletion{
        v = 1  // Compiler tells 'Escaping closure captures 'inout' parameter 'v'
        print("hello1 \(v)")
    }
}

var x = 0
testAdd(v:&x)

for comp in completion {
    comp()
}

我想知道除了将其作为 class 对象的引用类型之外,是否还有另一种方法可以让转义闭包更改周围变量(作为函数的 inout 参数)。

inout 被指定为具有“复制输入复制输出”行为。 x 的值在您调用该函数时被复制。在函数体中,可以修改 x 的副本,或其他任何内容。然后,当函数returns时,将副本再次复制,并赋值给原来的x。 “按引用调用”可以作为优化发生

这解释了为什么不能在转义闭包中修改 inout 参数。 swift 编译器不可能知道每个转义闭包 returns 何时将修改后的值复制回来。

您可以使用实际指针:

func testAdd(v: UnsafeMutablePointer<Int>) {
    addCompletion{
        v.pointee = 1 // you just need to change all references to "v" to "v.pointee"
        print("hello1 \(v.pointee)")
    }
}

或者,如果你不喜欢指针,你也可以这样做(改编自my other answer):

func testAdd(modifyV: @escaping ((inout Int) -> Void) -> Void) {
    addCompletion{
        modifyV { v in // here you can change v however you like!
            v = 1
            print("hello1 \(v)")
        }
    }
}

您只需要将来电者改为:

testAdd { [=12=](&x) }