Go代码如果没有一个无法到达的返回语句,就无法编译。

huangapple go评论86阅读模式
英文:

Go code doesn't compile without an unreachable return statement

问题

这是一个在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))
    }
}

错误:函数结束时没有返回语句

我在最后添加了一个return

func factorial(x uint) uint {
    if x == 0 {
        return 1
    } else {
        return x * (factorial(x - 1))
    }
    fmt.Println("这段代码永远不会执行")
    return 1
}

然后我得到了预期的输出120。

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

英文:

Here is the program to find the factorial of a number in Go:

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

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

The output for this function when called on input 5 is 120. However, if I add an else statement I get an error.

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

Error : function ends without a return statement

I added a return at the end :

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

and I get back the expected output of 120.

Why would the second case cause an error? Why in the third case even though the function never reaches the last return 1, it computes the correct output?

答案1

得分: 23

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

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

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

编译器要求返回或者panic必须在函数的最后一个位置。这个规则比要求进行完整的流控制分析来确定函数是否在没有返回的情况下到达末尾要简单得多(这在一般情况下非常困难),也比列举易于处理的情况要简单。而且,由于纯粹是词法的,这个错误不会因为函数内部控制结构中的常量等值的变化而自发地出现。

-rob

从另一个评论中in golang-nuts,我们可以推断出这个问题不会很快被“修复”:

这不是一个bug,而是一个故意的设计决策。

-rob

请注意,其他语言如Java允许使用else的规则。


2013年3月更新 - 它刚刚在Go1.1中发生了改变

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

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

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

更新:这个改变是向后兼容的,但是现有的代码中多余的“return”语句和panic的调用可以手动简化。这样的代码可以通过go vet来识别。

我提到的问题现在已经关闭,状态为“已修复”。

英文:

This is a well known problem of the compiler.

There is even an issue logged : http://code.google.com/p/go/issues/detail?id=65

In the words of one of the authors of the Go language:

> The compilers require either a return or a panic to be lexically last
> in a function with a result. This rule is easier than requiring full
> flow control analysis to determine whether a function reaches the end
> without returning (which is very hard in general), and simpler than
> rules to enumerate easy cases such as this one. Also, being purely
> lexical, the error cannot arise spontaneously due to changes in values
> such as constants used in control structures inside the function.
>
> -rob

From another comment in golang-nuts, we can infer it's not going to be "fixed" soon :

> It's not a bug, it's a deliberate design decision.
>
> -rob

Note that other languages like Java have rules allowing this else.


March 2013 EDIT - It just got changed in Go1.1 :

> Before Go 1.1, a function that returned a value needed an explicit
> "return" or call to panic at the end of the function; this was a
> simple way to make the programmer be explicit about the meaning of the
> function. But there are many cases where a final "return" is clearly
> unnecessary, such as a function with only an infinite "for" loop.
>
> In Go 1.1, the rule about final "return" statements is more
> permissive. It introduces the concept of a terminating statement, a
> statement that is guaranteed to be the last one a function executes.
> Examples include "for" loops with no condition and "if-else"
> statements in which each half ends in a "return". If the final
> statement of a function can be shown syntactically to be a terminating
> statement, no final "return" statement is needed.
>
> Note that the rule is purely syntactic: it pays no attention to the
> values in the code and therefore requires no complex analysis.
>
> Updating: The change is backward-compatible, but existing code with
> superfluous "return" statements and calls to panic may be simplified
> manually. Such code can be identified by go vet.

And the issue I mentioned is now closed with status "Fixed".

huangapple
  • 本文由 发表于 2012年11月22日 23:45:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/13516118.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定