在非void方法中缺少return语句编译

c.P*_*.u1 189 c# java oop

我遇到一种情况,其中一个非void方法缺少一个return语句,代码仍然编译.我知道while循环之后的语句是无法访问的(死代码),永远不会被执行.但为什么编译器甚至不警告返回什么?或者为什么一种语言允许我们使用无效循环且不返回任何内容的非void方法?

public int doNotReturnAnything() {
    while(true) {
        //do something
    }
    //no return statement
}
Run Code Online (Sandbox Code Playgroud)

如果我在while循环中添加break语句(甚至是条件语句),编译器会抱怨臭名昭着的错误:Method does not return a value在Eclipse和Not all code paths return a valueVisual Studio中.

public int doNotReturnAnything() {
    while(true) {
        if(mustReturn) break;
        //do something
    }
    //no return statement
}
Run Code Online (Sandbox Code Playgroud)

Java和C#都是如此.

Eri*_*ert 240

为什么一种语言允许我们使用具有无限循环且不返回任何内容的非void方法?

非void方法的规则是返回的每个代码路径都必须返回一个值,并且该规则在您的程序中得到满足:返回的零代码路径中的零返回值.规则不是"每个非void方法都必须有一个返回的代码路径".

这使您可以编写存根方法,如:

IEnumerator IEnumerable.GetEnumerator() 
{ 
    throw new NotImplementedException(); 
}
Run Code Online (Sandbox Code Playgroud)

这是一种非空洞的方法.为了满足界面,它必须是非空方法.但是让这个实现变得非法似乎很愚蠢,因为它不会返回任何东西.

由于a goto(记住,a while(true)只是一种更愉快的写法goto)而不是throw(这是另一种形式goto),你的方法有一个无法到达的终点是不相关的.

为什么编译器甚至不警告返回什么?

因为编译器没有很好的证据证明代码是错误的.有人写道while(true),这样做的人很可能知道他们在做什么.

我在哪里可以阅读有关C#中可达性分析的更多信息?

在这里查看我关于这个主题的文章:

ATBG:事实上和法律上的可达性

您也可以考虑阅读C#规范.

  • @SandeepPoonia:布尔标志可以在运行时更改,因为它不是const,因此循环不一定是无限的. (9认同)
  • @SandeepPoonia:在C#中,规范说`if`,`while`,`for`,`switch`等,对*常量*进行操作的分支结构被编译器视为无条件分支.*常量表达式*的确切定义在规范中.您的问题的答案在规范中; 我的建议是你读它. (9认同)

san*_*hat 38

Java编译器非常智能,可以找到无法访问的代码(while循环后的代码)

而且由于无法访问,在那里添加一个return声明是没有意义的(在while结束之后)

条件相同 if

public int get() {
   if(someBoolean) {   
     return 10;
   }
   else {
     return 5;
   }
   // there is no need of say, return 11 here;
}
Run Code Online (Sandbox Code Playgroud)

因为布尔条件someBoolean只能评估要么true或者false,也没有必要提供一个return 明确之后if-else,因为该代码是无法访问,而Java不抱怨.

  • 我不认为这真的解决了这个问题.这就解释了为什么在无法访问的代码中不需要`return`语句,而与OP代码中不需要*any*`return`语句的原因无关. (4认同)

Dan*_*rth 17

编译器知道while循环永远不会停止执行,因此该方法永远不会完成,因此return不需要语句.


Dav*_*ish 13

鉴于你的循环正在一个常量上执行 - 编译器知道它是一个无限循环 - 意味着该方法永远不会返回.

如果使用变量 - 编译器将强制执行规则:

这不会编译:

// Define other methods and classes here
public int doNotReturnAnything() {
    var x = true;

    while(x == true) {
        //do something
    }
    //no return statement - won't compile
}
Run Code Online (Sandbox Code Playgroud)


Kon*_*kov 11

Java规范定义了一个名为的概念Unreachable statements.您不允许在代码中包含无法访问的语句(这是编译时错误).你甚至不允许在while之后有一个return语句(true); Java中的声明.一个while(true);语句使下面的语句不可达的定义,所以你并不需要一个return说法.

请注意,虽然在一般情况下Halting问题是不可判定的,但是Unreachable Statement的定义比仅停止更严格.它正在决定一个程序肯定不会停止的非常具体的情况.从理论上讲,编译器无法检测所有无限循环和无法访问的语句,但它必须检测规范中定义的特定情况(例如,while(true)案例)


Ada*_*old 7

编译器非常聪明,可以发现你的while循环是无限的.

所以编译器无法为你考虑.它不能猜测为什么你写的代码.同样代表方法的返回值.如果你不对方法的返回值做任何事情,Java就不会抱怨.

那么,回答你的问题:

编译器分析您的代码,并在发现没有执行路径导致函数结束时,它就完成了OK.

无限循环可能有合理的原因.例如,许多应用程序使用无限主循环.另一个例子是可以无限期地等待请求的Web服务器.


Rex*_*err 7

在类型理论中,有一种称为底部类型的东西,它是所有其他类型(!)的子类,用于指示其他事物的非终止.(例外可以算作非终止类型 - 您不会通过正常路径终止.)

所以从理论的角度来看,这些非终止的语句可以被认为是返回Bottom类型的东西,这是int的子类型,所以你从类型的角度来看(从某种程度上)得到你的返回值.并且完全可以,没有任何意义,一个类型可以是包括int在内的所有其他类型的子类,因为你实际上从未返回过一个类型.

在任何情况下,通过显式类型理论,编译器(编译器编写者)都认识到在非终止语句之后要求返回值是愚蠢的:没有可能需要该值的情况.(让你的编译器在知道某些东西不会终止但是看起来你想让它返回一些东西时警告你可能会很高兴.但是对于样式检查器而言,这样做更好,因为你可能需要类型签名,出于某种其他原因(例如子类化),但你真的想要非终止.)


Gra*_*and 6

在没有返回适当值的情况下,函数无法达到目的.因此,编译器没有什么可抱怨的.


Tar*_*pta 5

Visual Studio有智能引擎来检测你是否输入了一个返回类型,然后它应该在函数/方法中有一个return语句.

与在PHP中一样,如果您还没有返回任何内容,则返回类型为true.如果没有返回,则编译器获得1.

截至此

public int doNotReturnAnything() {
    while(true) {
        //do something
    }
    //no return statement
}
Run Code Online (Sandbox Code Playgroud)

编译器知道虽然语句本身具有infinte性质,所以不要考虑它.如果你在while的表达式中写一个条件,PHP编译器将自动获得.

但是在VS的情况下它不会在堆栈中返回错误.