17

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

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

    return x * (factorial(x - 1))
}

在输入 5 上调用此函数时的输出为 120。但是,如果我添加一条else语句,则会出现错误。

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

错误 :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
}

我得到了 120 的预期输出。

为什么第二种情况会导致错误?为什么在第三种情况下,即使函数从未到达 last return 1,它也会计算正确的输出?

4

1 回答 1

23

这是编译器的一个众所周知的问题。

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

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

编译器要求 return 或 panic 在具有结果的函数中词法上最后。这条规则比需要完整的流控制分析来确定一个函数是否到达末尾而不返回(这通常很难)更容易,并且比枚举诸如此类的简单案例的规则更简单。此外,由于纯粹是词法的,错误不会由于函数内部控制结构中使用的常量等值的变化而自发产生。

-抢

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

这不是错误,而是经过深思熟虑的设计决定。

-抢

请注意,其他语言(如 Java)有允许这样做的规则else


2013 年 3 月编辑 -它刚刚在 Go1.1 中发生了变化

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

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

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

更新:更改是向后兼容的,但现有代码具有多余的“return”语句和对恐慌的调用可以手动简化。此类代码可以通过 go vet 识别。

我提到的问题现在以状态"Fixed"关闭。

于 2012-11-22T15:58:56.050 回答