以下输出“2”。这是为什么?它不应该递归并打印“210”吗?
package main
var f = func(x int) {}
func Bar() {
f := func(x int) {
if x >= 0 {
println(x)
f(x - 1)
}
}
f(2)
}
func main() {
Bar()
}
在全局范围内,
f
在这里定义为采用int
并且不执行(和返回)任何操作。
var f = func(x int) {}
当您在这里重新定义
f
时:
f := func(x int) {
if x >= 0 {
println(x)
f(x - 1)
}
}
在计算 func 之前,无法定义 f
,因此“新”f
函数不在其自己的范围内。所以f(x - 1)
仍然指的是全局函数。
您的代码中有两个不同的变量,名为
f
,位于不同的范围中。第一:
package main
var f = func(x int) {}
这在包范围内声明并初始化了一个函数变量
f
。然后:
func Bar() {
f := func(x int) {
if x >= 0 {
println(x)
f(x - 1)
}
}
f(2)
}
在 f
函数的范围内创建第二个 different_ 函数变量,
also,称为
Bar()
。
第二个
f
变量在初始化之前并不存在。为了说明这一点,请考虑这个演示问题的简化示例:
package main
func main() {
foo := foo + 1
println(foo)
}
您希望这段代码做什么?输出
1
或编译失败?答案应该是显而易见的。
即使
foo
的词法声明出现在初始值表达式之前,当评估该表达式时,
foo
还不存在。
如果引入了名为
foo
的打包作用域变量,则现在可以使用引用该值的表达式来初始化 foo
中的 main
:
package main
var foo = 2
func main() {
foo := foo + 1
println(foo)
}
现在可以正常编译并输出3
(
foo
中的
main
据说是包范围中的
shadow
)。
我们可以通过将包作用域函数变量
foo
重命名为其他内容(例如 f
)来说明代码中的相同问题。然后你应该发现你的代码不再编译:
pf
您可以在这个游乐场看到这一点。解决方案希望是显而易见的:更改分配给
package main
var pf = func(x int) {}
func Bar() {
f := func(x int) {
if x >= 0 {
println(x)
f(x - 1) // << compilation error: `f` does not exist
}
}
f(2)
}
func main() {
Bar()
}
的函数的代码,使其引用 f
:
pf
那么很明显, package main
var pf = func(x int) {}
func Bar() {
f := func(x int) {
if x >= 0 {
println(x)
pf(x - 1) // << compilation error: `f` does not exist
}
}
f(2)
}
func main() {
Bar()
}
中的函数没有引用自身。
关键在于
f
中的函数没有名称
。
f
不是函数的名称,而只是变量的名称,该变量保存对匿名函数的引用。
进一步思考,你会发现匿名函数是无法递归的。