为什么Go不允许嵌套函数声明(函数内部的函数)?

cor*_*zza 71 declaration function go

编辑:如果不清楚我在问什么:不允许嵌套函数声明可以缓解哪些问题?

Lambdas按预期工作:

func main() {
    inc := func(x int) int { return x+1; }
}
Run Code Online (Sandbox Code Playgroud)

但是,不允许在声明中使用以下声明:

func main() {
    func inc(x int) int { return x+1; }
}
Run Code Online (Sandbox Code Playgroud)

出于什么原因,不允许使用嵌套函数?

Nic*_*ood 46

我认为有三个原因可以解释为什么不允许使用这个明显的功能

  1. 这会使编译器稍微复杂化.目前,编译器知道所有功能都在顶层.
  2. 它会产生一类新的程序员错误 - 你可以重构一些东西并意外地嵌套一些函数.
  3. 对函数和闭包使用不同的语法是一件好事.制作一个闭包可能比制作一个函数更昂贵,所以你应该知道你正在这样做.

这些只是我的观点 - 我还没有看到语言设计师的正式声明.

  • Pascal(至少它是Delphi的化身)使它们变得正确和简单:嵌套函数的行为与常规函数一样,但也可以访问其封闭函数范围内的变量.我认为这些都难以实施.另一方面,由于编写了大量Delphi代码,我不确定我是否非常需要嵌套函数:偶尔他们会感觉很漂亮,但是它们往往会破坏封闭的功能,使其几乎无法读取.同时访问其父项的参数可能会使程序难以阅读,因为这些变量是隐式访问的(不作为形式参数传递). (2认同)

Mat*_*son 26

当然可以.您只需将它们分配给变量:

func main() {
    inc := func(x int) int { return x+1; }
}
Run Code Online (Sandbox Code Playgroud)

  • 值得注意的是,您不能递归地调用此类函数(inc)。 (8认同)
  • 为了递归调用它,你需要转发声明`var inc func(int) int` (5认同)

pet*_*rSO 23

常见问题(FAQ)

为什么Go没有X功能?

每种语言都包含新颖的功能,并省略了某些人最喜欢的功能.Go的设计着眼于编程的幸福性,编译的速度,概念的正交性以及支持并发和垃圾收集等功能的需要.您最喜欢的功能可能会丢失,因为它不适合,因为它会影响编译速度或设计的清晰度,或者因为它会使基本系统模型太难.

如果您对Go缺少功能X感到困扰,请原谅我们并调查Go确实具有的功能.您可能会发现它们以缺乏X的有趣方式进行补偿.

什么能够证明添加嵌套函数的复杂性和费用是正确的?如果没有嵌套函数,你不能做什么?等等.

  • 公平地说,我认为任何人都没有证明允许嵌套函数会导致任何特殊的复杂性.另外,虽然我同意引用的哲学,但我不确定将嵌套函数称为"特征"是否合理,而不是将它们作为一个特征引用.你知道允许嵌套函数允许的任何复杂性吗?我假设他们只是lambdas的语法糖(我想不出任何其他合理的行为). (17认同)

Koa*_*la3 12

这是在嵌套函数中实现嵌套函数和函数的一种方法

package main

    import "fmt"

    func main() {
        nested := func() {
            fmt.Println("I am nested")

            deeplyNested := func() {
                fmt.Println("I am deeply nested")
            }

            deeplyNested()
        }

        nested()
    }
Run Code Online (Sandbox Code Playgroud)


小智 11

Go 中允许嵌套函数。您只需要将它们分配给外部函数中的局部变量,并使用这些变量调用它们。

例子:

func outerFunction(iterations int, s1, s2 string) int {
    someState := 0
    innerFunction := func(param string) int {
        // Could have another nested function here!
        totalLength := 0
        // Note that the iterations parameter is available
        // in the inner function (closure)
        for i := 0; i < iterations; i++) {
            totalLength += len(param)
        }
        return totalLength
    }
    // Now we can call innerFunction() freely
    someState = innerFunction(s1)
    someState += innerFunction(s2)
    return someState
}
myVar := outerFunction(100, "blah", "meh")
Run Code Online (Sandbox Code Playgroud)

内部函数对于本地 goroutine 来说通常很方便:

func outerFunction(...) {
    innerFunction := func(...) {
        ...
    }
    go innerFunction(...)
}
Run Code Online (Sandbox Code Playgroud)

  • @MichałZabielski:如果在定义之前声明它,则可以递归调用它。 (8认同)
  • 这个答案只是重复了问题已经说过的话。 (2认同)