为什么 Swift 在使用转义闭包时需要 Inout 参数的本地副本?

问题描述 投票:0回答:1

我刚刚发现 Swift 有像 C 一样的指针。我正在尝试让这段代码工作,而我所做的唯一方法就是制作本地副本。

这个工作正常。

func myMult(_ x: Int, _ computeValue: @escaping () -> Int) -> Int { 
    if x == 0 {
        return 0
    } else if x == 1 {
        return computeValue()
    } else {
        return computeValue() + myMult(x - 1, computeValue)
    }
}


func myDelay(_ th: @escaping () -> Int) -> (Bool, () -> Int) {
    return (false, th)  
}


func myForce(_ p: inout (Bool, () -> Int) ) -> Int {
    if p.0 {
        return p.1()
    } else {
        let local_p = p.1
        p.0 = true
        p.1 = { local_p() }
    }
    
    return p.1()
}


// (false, (Function))
var myDelayedResult = myDelay({2 + 3})

// false
delayedResult.0
// 5
delayedResult.1()

// 1500
myMult(300, {myForce(&delayedResult)})

// (true, (Function))
myDelayedResult

现在,如果我删除 local_p,我会收到错误。

我正在学习C,C有声明一个点和解引用一个指针,还有获取变量内存地址的运算符。

ChatGPT 说明:

  • Swift 要求转义闭包不捕获 inout 参数,因为 inout 参数仅在函数调用期间有效。将 inout 参数存储在转义闭包中可能会造成无效内存访问。
func myForce(_ p: inout (Bool, () -> Int) ) -> Int {    
    if p.0 {
        return p.1()
    } else {
        p.0 = true
        // error: Escaping closure captures 'inout' parameter 'p'
        p.1 = { p.1() }
    }
    
    return p.1()
}

现在考虑到这一点,我的问题是,我需要取消引用 p 吗?我尝试了 p.1 = { inout p.1() } 但收到错误。

找到了这个转义闭包捕获“inout”参数但它仍然没有回答我的问题。

任何解释都会很好。

swift functional-programming memory-address inout
1个回答
0
投票

即使有了这个看起来很有趣、没有 inout 的功能性东西,我仍然必须使用本地到本地。我不确定是否有办法解决它。 (顺便说一句,我仍然不知道如何将 myDelay 实现为参考事物,例如数组,而不使用自定义的)。

func myMult() -> (Int, @escaping () -> Int) -> Int { 
    return { x, yThunk in
        if x == 0 {
            return 0
        } else if x == 1 {
            return yThunk()
        } else {
            return yThunk() + myMult()(x - 1, yThunk)
        }
    }
}
    

func myDelay() -> (@escaping () -> Int) -> (Bool, () -> Int) {
    return { th in (false, th)}
}


func myForce2() -> ((Bool, () -> Int)) -> () -> Int {
    return { (p: (Bool, () -> Int)) in
        var tuple = p
        if tuple.0 {
            return tuple.1
        } else {
            let result = tuple.1()
            // Cannot assign to property: 'p' is a 'let' constant
            // if used without a local
            tuple.0 = true
            tuple.1 = { result }
            return tuple.1
        }
    }
}

var myDelayedResult = myDelay()(){2 + 3}

// false
print(myDelayedResult.0)
// 5
print(myDelayedResult.1())

// 1500
myMult()(300, {myForce2() (myDelayedResult)()})

// (false, (Function))
myDelayedResult

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.