如果没有无法访问的返回语句,Go代码将无法编译

sre*_*sad 17 go

以下是在Go中查找数字的阶乘的程序:

func factorial(x uint) uint {
    if x == 0 {
        return 1
    }

    return x * (factorial(x - 1))
}
Run Code Online (Sandbox Code Playgroud)

在输入5上调用此函数的输出是120.但是,如果我添加一个else语句,我会收到错误.

func factorial(x uint) uint {
    if x == 0 {
        return 1
    } else {
        return x * (factorial(x - 1))
    }
}
Run Code Online (Sandbox Code Playgroud)

错误: function ends without a return statement

return在最后添加了一个:

func factorial(x uint) uint {
    if x == 0 {
        return 1
    } else {
        return x * (factorial(x - 1))
    }
    fmt.Println("this never executes")
    return 1
}
Run Code Online (Sandbox Code Playgroud)

我得到了预期的120输出.

为什么第二种情况会导致错误?为什么在第三种情况下,即使函数永远不会到达最后一个return 1,它计算正确的输出?

Den*_*ret 23

这是编译器的众所周知的问题.

甚至还记录了一个问题:http://code.google.com/p/go/issues/detail?id = 65

用Go语言的一位作者的话来说:

编译器要求返回或恐慌在具有结果的函数中在词法上最后.这个规则比要求全流控制分析更容易确定一个函数是否在没有返回的情况下到达终点(一般来说这是非常难的),并且比规则简单地枚举简单的案例(例如这个)更简单.此外,纯粹是词汇,由于值的变化(例如函数内部控制结构中使用的常量),错误不会自发产生.

-抢

根据golang-nuts中的另一条评论,我们可以推断它不会很快被"修复":

这不是一个错误,这是一个刻意的设计决定.

-抢

请注意,像Java这样的其他语言允许这样做else.


2013年3月编辑 -在Go1.1中刚刚改变:

在Go 1.1之前,返回值的函数需要在函数末尾显式"返回"或调用panic; 这是让程序员明确函数含义的简单方法.但是在很多情况下,最终的"返回"显然是不必要的,例如只有无限"for"循环的函数.

在Go 1.1中,关于最终"返回"语句的规则更加宽松.它引入了终止语句的概念,该语句保证是函数执行的最后一个语句.例子包括没有条件的"for"循环和"if-else"语句,其中每一半都以"return"结尾.如果函数的最终语句可以在语法上显示为终止语句,则不需要最终的"返回"语句.

请注意,该规则纯粹是语法规则:它不关注代码中的值,因此不需要复杂的分析.

更新:更改是向后兼容的,但可以手动简化具有多余"返回"语句和调用恐慌的现有代码.这样的代码可以通过兽医来识别.

我提到的问题现在已关闭,状态为"已修复".