如C,Java中,和C ++语言在使用时都需要围绕整个表达式括号if
,while
或switch
。
if (true) {
// Do something
}
相对于
if true {
// Do something
}
我觉得这很奇怪,因为括号是多余的。在此示例中,true
是一个单独的表达式。括号不会以我所知的任何方式改变其含义。为什么存在这种奇怪的语法?为什么如此常见?我不知道有什么好处吗?
if
语句的一部分,它们只是创建了复合语句。
如C,Java中,和C ++语言在使用时都需要围绕整个表达式括号if
,while
或switch
。
if (true) {
// Do something
}
相对于
if true {
// Do something
}
我觉得这很奇怪,因为括号是多余的。在此示例中,true
是一个单独的表达式。括号不会以我所知的任何方式改变其含义。为什么存在这种奇怪的语法?为什么如此常见?我不知道有什么好处吗?
if
语句的一部分,它们只是创建了复合语句。
Answers:
需要某种方式来告知条件在何处结束以及分支开始于何处。有许多不同的方法可以做到这一点。
在一些语言中,有没有条件语句可言,如在Smalltalk,自考,新话,IO,伊欧凯,SEPH和花式。与其他方法一样,条件分支只是作为常规方法简单实现的。该方法在布尔对象上实现,并在布尔上被调用。这样,条件就是方法的接收者,并且两个分支是两个参数,例如在Smalltalk中:
aBooleanExpression ifTrue: [23] ifFalse: [42].
如果您更熟悉Java,则等效于以下内容:
aBooleanExpression.ifThenElse(() -> 23, () -> 42);
在Lisp语言家族中,情况类似:条件只是普通函数(实际上是宏),第一个参数是条件,第二个和第三个参数是分支,因此它们只是普通函数参数,并且不需要特别的分隔它们:
(if aBooleanExpression 23 42)
某些语言使用关键字作为分隔符,例如Algol,Ada,BASIC,Pascal,Modula-2,Oberon,Oberon-2,Active Oberon,Component Pascal,Zonnon,Modula-3:
IF aBooleanExpression THEN RETURN 23 ELSE RETURN 42;
在Ruby中,您可以使用关键字或表达式分隔符(分号或换行符):
if a_boolean_expression then 23 else 42 end
if a_boolean_expression; 23 else 42 end
# non-idiomatic, the minimum amount of whitespace required syntactically
if a_boolean_expression
23 else 42 end
# idiomatic, although only the first newline is required syntactically
if a_boolean_expression
23
else
42
end
Go要求分支必须是块,并且不允许使用表达式或语句,这使花括号成为必需。因此,虽然您可以根据需要添加括号,但不需要括号。Perl6和Rust在这方面是相似的:
if aBooleanExpression { return 23 } else { return 42 }
某些语言使用其他非字母数字字符来分隔条件,例如Python:
if aBooleanExpression: return 23
else: return 42
最重要的是:您需要某种方法来告知条件在何处结束以及分支开始于何处。这样做的方法很多,括号只是其中之一。
仅在使用大括号时才需要括号。
if true ++ x;
例如,如果没有它们,就会变得模棱两可。
if
:基本,汇编,python,bash / zsh,tcl,批处理,brainfuck或机器代码。仅if
当语言被设计为依赖括号时,才缺少括号。
if Condition then ...
。
{}
强制性的,因此不需要在表达式周围加括号。不仅不需要parens,而且如果我记得正确添加parens会导致编译错误-禁止使用它们
在括号中if
的语句没有意义的算术表达式中使用括号一样。算术表达式中的括号用于将表达式分组在一起。if
语句中的括号用于分隔布尔表达式;也就是说,将布尔表达式与if
语句的其余部分区分开。
在if
语句中,括号不执行分组功能(尽管在if
语句内,您仍可以使用括号对算术表达式进行分组。然后,括号的外部集用于界定整个布尔表达式)。将它们设为必需可以简化编译器,因为编译器可以依赖始终存在于其中的那些括号。
IF primary_expression statement
。注意,后者同样是明确的。
primary_expression
不能将表达式声明中的后缀运算符与前缀运算符区分开。要复制Telastyn的答案,if true ++ x;
。同样,如果存在空语句,if a & f;
则可以是&
条件内部的空语句和二进制,也可以是语句&
开头的一元。但是,当括号匹配时,开头恰好有一个匹配项(
IDENTIFIER
,CONSTANT
,STRING_LITERAL
和'(' expression ')'
。
正如其他人已经部分指出的那样,这是由于表达式也是有效的语句,并且在只有一个语句的块的情况下,您可以删除花括号。这意味着以下内容不明确:
if true
+x;
因为它可以解释为:
if (true + x) {}
代替:
if (true) {+x;}
许多语言(例如Python)使您可以避免使用括号,但仍然具有结束条件标记:
如果为True : + x
但是,您可以定义一个永远不需要括号的语言是正确的:表达式不是有效语句的语言将不会出现此问题。
不幸的是,这意味着:
++x;
functionCall(1,2,3);
将不是有效的语句,因此您必须引入一些怪异的语法才能执行此类操作而无需创建表达式。一种简单的方法是在表达式前面加上一个标记,例如[statement]
:
[statement] ++x;
[statement] functionCall(1,2,3);
现在,由于您必须编写,歧义消失了:
if true
[statement] ++x;
但是如您所见,我看不到这种语言的广泛使用,因为将括号括在if
-condition(或:
末尾)周围要比为每个表达式语句放置这样的标记要好得多。
注意:使用[statement]
标记只是我能想到的最简单的语法。但是,对于表达式和语句,您可能有两种完全不同的语法,它们之间没有歧义,不需要这样的标记。问题是:由于要在表达式或语句中执行相同的操作,因此您必须使用完全不同的语法,因此该语言将非常奇怪。
想到的是,有两种没有这种显式标记的单独语法,例如:强制语句使用unicode符号(因此,不是for
使用字母f
,o
和的unicode变体r
,而表达式是仅ASCII。
discard
在Nim中显式地指定其值。但是,这样做只是为了类型安全,而不是出于语法原因。
?
例如,simbol实际上是PP之后的函数)。没有;
。当然,它需要一个用于续行的标记,但是不建议这样做。harbour.github.io/doc/clc53.html#if-cmd。该编译器既快速又简单(使用Bison / Flex创建)。
if
,while
ECC被限制相比,在其他语言中使用的通用的表达式。当然:如果您有两个以上的语法类别(例如陈述,表达,逻辑表达,咖啡制作表达等),则可以交易一些自由。
C系列语言通常要求使用这些括号,但并不通用。
一个Perl 6的的更明显的语法变化是,他们修改了语法,这样你就没有给周围的括号if
,for
和类似的声明的条件。因此,类似这样的事情在Perl 6中是完全有效的:
if $x == 4 {
...
}
照原样
while $queue.pop {
...
}
但是,由于它们只是表达式,您可以根据需要在其周围加上括号,在这种情况下,它们只是普通的分组形式,而不是C,C#,Java等语言中语法的必需部分。
Rust在该部门的语法与Perl 6类似:
if x == 4 {
...
}
在我看来,受现代C语言启发的语言的一个特征是查看此类内容并想删除它们。
if
或循环构造,需要使用paren,例如in if ( $x == 4 ) { ... }
或foreach my $foo ( @bar ) { ... }
。使用后缀表示法时,括号是可选的,如return unless $foo;
或中所示++$x while s/foo/bar/g;
。
有一个方面令我感到惊讶,现有的答案都没有提出。
C以及许多C派生和相似项具有一个特点,即赋值是赋值。这样的结果是可以在期望值的地方使用分配。
这使您可以编写类似
if (x = getValue() == 42) { ... }
要么
if (x == y = 47) { ... }
要么
unsigned int n = 0 /* given m == SOME_VALUE */;
while (n < m && *p1++ = *p2++) { n++; }
(这被隐式地视为while (n < m && *p1++ = *p2++ != 0) { n++; }
因为C将非零视为true;顺便说一句,我认为这与C标准库中的strncpy()差不多)
甚至
if (x = 17);
这都是有效的。并非所有语法有效的组合都一定有用(现代编译器特别警告条件语句中的赋值,因为它是一个常见错误),但其中某些实际上有用。
如果没有明确的方法来确定条件表达式的开始和结束位置,则解析此类语句可能会更加困难。
括号已用于从函数参数中分隔函数名称,因此我想它们似乎也很自然地从关键字参数中分隔关键字。
当然,可以定义其他语法来执行相同的操作。但是这样做会增加复杂性,尤其是在解析器中,然后在很大程度上需要处理两组不同的语法。早在设计C时,计算能力(无论是数字运算能力,工作内存还是存储容量)都极为有限。几乎不用付出任何代价就可以降低复杂性的任何事情,几乎肯定是可喜的变化。
在今天,使用括号似乎有些陈旧,但与拥有某种语言的人并不熟悉的情况相比,与能够表达相同内容的其他语法相比,这会损害可读性。
原因主要是历史。
在编写第一个C编译器时,计算机的ram,cpu和编译器非常有限,它们是用“手工”编写的,几乎没有什么工具可以帮助编译器编写者。因此,复杂的规则在编译器中实现成本很高。C ++,C#,Java等都是为了使C程序员易于学习而设计的,因此没有进行“不必要的”更改。
在“ c like”语言中,条件语句(if, while, etc
)不需要显式的block
off代码,您只需使用简单的语句即可。
if (a == d) doIt()
或者您也可以结合在一起的语句为compound statement
通过将它们与{}
我们希望编译器找到我们所犯的错误,并给出我们可以理解的错误消息。
Java和C ++都是在C成为非常流行的编程语言之后开发的。在设计每种语言时,要考虑的一个因素是它将吸引C程序员并吸引这些程序员使用新语言。(我曾经是他们成功吸引的C程序员之一。)C ++的设计目的是(几乎)可以与C代码互换。为了支持这些目标,无论是C ++和Java采用了很多C'S语法,包括周围的条件括号if
,while
和switch
语句。
因此,所有这些语言在这些语句的条件周围都需要括号的原因是因为C确实需要这样做,而问题实际上就是C为什么需要这些括号。
本文的主要作者之一丹尼斯·里奇(Dennis Ritchie)在本文中描述了C语言的起源 (有人甚至可以说是其开发的主要作者)。如该文章所述,C最初是在1970年代初开发的,它是用于主存空间非常有限的计算机的系统编程语言。希望有一种比汇编语言更高级的语言,但是鉴于可用的资源,解析该语言的简便性也很重要。要求括号将使识别条件代码相对容易。
也许还可以推断出使用较少字符来编写程序的能力被认为是一种优势,并且两个括号所占用的空间比THEN
当时FORTRAN和其他高级语言所使用的关键字少;实际上,由于括号也可以代替空格作为符号的分隔符,if(a==b)
因此比短了四个完整字符IF a==b THEN
。
无论如何,在人类阅读,编写和理解用C编写的程序的容易程度,编译器解析和编译用C编写的程序的难易程度以及多少千字节(!)之间必须取得一定的平衡。程序源和编译器本身都将需要它。和周围的条件括号if
,while
和switch
语句是人们如何选择罢工C的设计平衡
正如其他几个答案所证明的那样,一旦您摆脱了C语言开发的特殊环境,就已经将各种其他形式的语法用于各种编程语言的条件。因此,括号实际上只是由少数人在历史上的某个特定时间在一定约束下做出的设计决定而做出的。
这里有许多理由认为,如果没有括号,该语法将是模棱两可的,并且无声地暗示这将是一种糟糕的情况,甚至是不可能的情况。
实际上,语言有很多方法可以处理歧义。运算符优先级只是该主题的一个实例。
不,模棱两可不是括号的原因。我想一个人可以简单地创建一个C版本,该C版本不需要条件周围的括号(因此使它们成为可选的),并且在所有情况下仍可以创建有效的代码。的示例if a ++ b;
可以解释为等同于if (a) ++b;
或if (a++) b;
,无论哪种看起来更合适。
为什么丹尼斯·里奇(Dennis Ritchie)选择使()为强制性(并因此为许多派生语言创造了这种模因)的问题是一种语言学的问题。我猜想这样的想法清楚地表明,条件是一种表达,而不是命令是思想之源。
实际上,C被设计为使用一遍解析器可解析的。在条件周围使用带有强制括号的语法可支持此方面。
THEN
)。