为什么要接住捕捉,必须使用方括号?


38

您可以使用多种语言(至少需要Java,也可以考虑使用C#吗?)

if( condition )
    singleStatement;

while( condition )
    singleStatement;

for( var; condition; increment )
    singleStatement;

因此,当我只有一条语句时,不需要使用添加新的作用域{ }。为什么我不能通过try-catch做到这一点?

try
    singleStatement;
catch(Exception e)
    singleStatement;

关于try-catch是否有一些特别之处,需要始终拥有新的作用域或其他内容?如果是这样,编译器无法解决该问题吗?


3
吹毛求疵的位置:严格地说为for零件名称应该像initialconditionstep作为initial不需要定义一个变量,step不必是一个增量。
约阿希姆·绍尔

4
作为旁注,D不需要在单个语句周围加括号,请尝试使用catch块
棘手怪胎

13
我认为真正的问题是相反的:为什么某些构造允许使用“裸”语句?为了保持一致性,必须在所有地方都必须使用花括号。
UncleZeiv

3
@UncleZeiv-如果您认为跟随其后的if始终是单个语句,并且用大括号括起来的多个语句组成一个语句,这并不是不一致的。但我那些谁始终把括号,无论如何,这样的一个...
detly

1
我也倾向于编写大括号,但是当我有直接退出点(例如throw和)时,我喜欢不必编写它们return,就像@detly所说的那样,如果您将大括号视为单个语句组,则找不到它不一致。我从不了解人们提到的这些“大量编码错误”。人们需要开始注意自己的工作,使用适当的缩进并进行单元测试:P从来没有遇到过问题……
Svish

Answers:


23

IMO,它们之所以包含在Java和C#中,主要是因为它们已经存在于C ++中。那么,真正的问题是C ++为什么会这样。根据C ++的设计和演变(第16.3节):

try关键字是完全冗余的,所以是{ }除了其中多个语句在try块或一个处理程序实际使用的支架。例如,允许:

int f()
{
    return g() catch(xxii) { // not C++
        error("G() goofed: xxii");
        return 22;
    };
}

但是,我发现很难解释这一点,因为引入了冗余是为了从混乱的用户中节省支持人员。

编辑:至于为什么这会造成混淆,我认为只需要查看@Tom Jeffery的答案中的不正确断言(尤其是收到的赞成票的数量)就可以意识到会有问题。对于解析器而言,这实际上与将elses与ifs 匹配没有什么不同-缺少用于强制其他分组的花括号,所有 catch子句都将与最新的匹配throw。对于那些包含它的错误的语言,finally子句也将这样做。从解析器的角度来看,这与当前情况几乎没有什么不同,尤其是从语法的角度来看,实际上没有什么可将这些catch子句归为一类的了,方括号将由catch 子句,而不是catch子句本身。

从编写解析器的角度来看,差异几乎很小,无法察觉。如果我们从这样的事情开始:

simple_statement: /* won't try to cover all of this */
                ;

statement: compound_statement
         | simple_statement
         ;

statements: 
          | statements statement
          ;

compound_statement: '{' statements '}'

catch_arg: '(' argument ')'

那么区别将是:

try_clause: 'try' statement

和:

try_clause: 'try' compound_statement

同样,对于catch子句:

catch_clause: 'catch' catch_arg statement

catch_clause: 'catch' catch_arg compound_statement

完整的try / catch块的定义根本不需要更改。不管哪种方式,它都是这样的:

catch_clauses: 
             | catch_clauses catch_clause
             ;

try_block: try_clause catch_clauses [finally_clause]
         ;

[这里我[whatever]用来表示可选的内容,而我省略了a的语法,finally_clause因为我认为它与问题无关。]

即使你不尝试按照所有的类yacc语法定义那里,点可以很容易总结:这一句(以出发try_block)是一个地方catch条款会被配对上try的条款-它仍然准确的无论是否需要大括号,都相同。

重申/总结:括号组一起控制语句通过catchS,但这样做不是catchŞ自己。这样,那些括号绝对不会决定哪个catch匹配try。对于解析器/编译器,无论哪种方式,任务都同样容易(或困难)。尽管如此,@ Tom的答案(以及收到的赞成票的数量)充分说明了这样的变化几乎肯定会使用户感到困惑。


该OP是问周围的尝试和两个支架catch块,而这似乎是参考周围那些尝试(第一款可以被理解为同时引用,但代码说明仅是前者)...你能澄清?
Shog9

@ Mr.CRT:否则,“捕获块”将被称为“处理程序”,有关该处理程序,请参见上面的引用。
杰里·科芬

3
h,只是编辑了我的评论以消除这种歧义。我要说的是,如果用更长的篇幅说明无括号的构造如何工作的,那么这可能比汤姆(上)更有效,但是以一种令人困惑的方式(比利对汤姆的回答的评论似乎暗示它不可能成功,我认为这是不正确的)。
Shog9

@JerryCoffin感谢您扩大回答:现在对我来说更清楚了。

try return g(); catch(xxii) error("G() goofed: xxii");谁应该还整洁IMO
alfC 2014年

19

回答为什么某些单语句结构需要括号而不是其他语句时,Eric Lippert写道:

在许多地方,C#要求使用大括号的语句块而不是允许使用“裸”语句。他们是:

  • 方法,构造函数,析构函数,属性访问器,事件访问器或索引器访问器的主体。
  • 最后,尝试,捕获,检查,未检查或不安全区域的障碍。
  • 语句lambda或匿名方法的块
  • if或循环语句的块,如果该块直接包含局部变量声明。(也就是说,“ while(x!= 10)int y = 123;”是非法的;您必须将声明括起来。)

在每种情况下,都有可能针对单个无括号的陈述是合法的特征提出明确的语法(或启发式方法来消除歧义的语法)。但是,重点是什么?在每种情况下,您都希望看到多个语句。单个语句是罕见的,不太可能的情况。对于这些非常不可能的情况,使语法变得模棱两可似乎是不值得的。

换句话说,对于编译器团队来说,实现它的成本要比合理的高,因为这样做会带来边际收益。


13

我认为这是为了避免悬而未决的样式问题。以下内容将不明确...

try
    // Do stuff
try
    // Do  more stuff
catch(MyException1 e1)
    // Handle fist exception
catch(MyException2 e2)
    // So which try does this catch belong to?
finally
    // and who does this finally block belong to?

这可能意味着:

try {
   try {

   } catch(Exception e1) {

   } catch(Exception e2) {

   } 
} finally {

} 

要么...

try {
   try {

   } catch(Exception e1) {

   } 
} catch(Exception e2) {

} finally {

} 

24
这种歧义适用于是否以及是否同样适用。问题是:为什么为什么允许ifswitch语句而不允许try / catch
Dipan Mehta

3
@Dipan公平点。我想知道这是否只是Java / C#的问题,就是通过允许无括号的if来试图与C之类的旧语言保持一致。虽然try / catch是一种较新的结构,所以语言设计师认为可以打破传统。
汤姆·杰弗里斯

我尝试至少对C和C ++回答强迫症。
Dipan Mehta

6
@DipanMehta:因为对于这种if情况,没有多个可能的悬挂子句。只需说出“将else绑定到最里面的if上”,并轻松完成即可。但是对于try / catch不起作用。
Billy ONeal

2
@Billy:我认为您正在掩盖if / if else中存在的潜在歧义。很容易说“这很容易说出来”-但这是因为要解决歧义有一个硬性规则,顺便说一句,这是不允许的某些不使用方括号的结构。杰里的回答暗示,这为避免混淆而做出的有意识的选择,但可以肯定的是,它可以起作用-就像它在“是否/如果存在”时“起作用”一样。
Shog9

1

我认为主要原因是,您在C#中几乎无能为力,只需要一排try / catch块即可。(我现在想不出我的头顶)。就catch块而言,您可能有一个有效的观点,例如,用一行语句记录某件事,但就可读性而言,要求{}更有意义(至少对我来说)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.