SWIFT递归:函数与闭包

x33g5p2x  于 2022-10-23  发布在  Swift
关注(0)|答案(2)|浏览(190)

这将编译以下内容:

let badger = get_closure()

func get_closure() -> (Int) -> Void {
  return { (x: Int) -> Void in
    print(x)
    if x > 4 {
      return
    } else {
      badger(x + 1)
    }
  }
}

badger(1)

这不适用于循环引用错误:

let badger = get_closure()

let get_closure = { () -> (Int) -> Void in
  return { (x: Int) -> Void in
    print(x)
    if x > 4 {
      return
    } else {
      badger(x + 1)
    }
  }
}

badger(1)

为什么?我认为func语法只是对第二种更明确的语法的补充。

eanckbw9

eanckbw91#

事实是,第一个可以工作的是一个长期存在的bug/quirk in the compiler,而不是一个预期的功能。它基于undefined behavior,编译器很难检测到。您可以通过将您的工作代码 Package 在一个函数中来演示它是顶级声明的怪癖,并且可以看到它的失败与您的第二个示例非常相似:

func f() {
    let badger = get_closure()

    func get_closure() -> (Int) -> Void {  // ERROR: Closure captures 'badger' before it is declared
        return { (x: Int) -> Void in
            print(x)
            if x > 4 {
                return
            } else {
                badger(x + 1)
            }
        }
    }

    badger(1)
}

badger这样的顶级、全局声明的关键特性是,它们的计算很慢,所以赋值实际上发生在函数声明之后。在您的第二个示例中,两个变量都是惰性的,因此返回顺序。但依赖这一事实是危险的,正如链接的论坛帖子中所讨论的那样。
在探索微妙的SWIFT行为时,我总是建议构建一个命令行应用程序,并将测试代码放在函数中,以消除Playground和顶级可执行代码的奇怪之处。(在这种情况下,操场并不重要,但它经常被提到。)

dphi5xsq

dphi5xsq2#

很难理解这种方法应该在哪里使用,但如果你真的想这样做,那么试试这个:

let get_closure: (Int) -> Void = { x in
      print(x)
    if x > 4 {
      return
    } else {
      badger(x + 1)
    }
}

let badger = get_closure

badger(1)

因变量的初始化顺序通常很重要。如果在关闭后赋值,则不会出现错误:

let get_closure = { () -> (Int) -> Void in
  return { (x: Int) -> Void in
    print(x)
    if x > 4 {
      return
    } else {
      badger(x + 1)
    }
  }
}

let badger = get_closure()

badger(1)

相关问题