[英]Why can't you create a 1 statement function without curly braces?
因此,在大多数编程语言中,如果您使用循环或if,如果其中只有一个语句,则可以在没有花括号的情况下执行此操作,例如:
if (true)
//Single statement;
for (int i = 0; i < 10; i++)
//Single Statement
while (true)
//Single statement
但是,它不适用于函数,例如:
void myFunction()
//Single Statement
所以,我的问题,为什么它不适用于功能?
C ++需要它消除一些构造的歧义:
void Foo::bar() const int i = 5;
现在const
属于bar
还是i
?
因为语言语法禁止你这样做。
Java语法定义了如下方法:
MethodDeclaration:
MethodHeader MethodBody
方法体如:
MethodBody:
Block
;
这意味着块(见下文)或单个分号
Block:
{ BlockStatementsopt }
和一个块作为大括号内的一个或多个语句。
但是,if定义为:
IfThenStatement:
if ( Expression ) Statement
在关闭后不需要块的情况下,因此单行是可以的。
他们为什么选择这样定义? 人们只能猜测。
语法可以在这里找到: http : //docs.oracle.com/javase/specs/jls/se7/html/index.html
这不是一个规则,在某些语言中你可以(Python?是的,我知道这是真正做作的例子:))),在其他你不能。
您可以很好地将您的问题扩展到类和名称空间,例如,为什么不:
namespace Example
class Foo : public Bar
public: std::string myMethod()
return "Oh noes!";
对? 在每个级别,这只是一个项目,那么为什么不到处跳过括号呢?
答案同时简单而复杂。
简单来说,它是关于可读性的。 请记住,您可以根据需要布置代码, 因为编译器通常会丢弃空格 :
namespace Example class Foo : public Bar public: std::string myMethod() return "Oh noes!";
嗯,开始看起来不可读。 请注意,如果您添加大括号
namespace Example { class Foo : public Bar { public: std::string myMethod() {return "Oh noes!";}}}
然后,奇怪的是,它变得有些可理解。
实际问题不是可读性(谁在乎呢?我当然是在开玩笑)但在后者:理解。 您不仅必须能够理解代码 - 编译器必须。 对于编译器来说,没有“哦,这看起来像功能”这样的东西。 编译器必须绝对确定它是一个函数。 此外,它必须完全确定它的起始位置,结束位置,等等。 它必须这样做而不必过多地查看空格,因为C系列语言允许您以任意数量添加它们。
那么,让我们再看看打包的无支撑示例
namespace Example class Foo : public Bar public : std::string myMethod() return "Oh noes!";
^ ^ ^^
我标记了一些有问题的符号。 假设您可以定义处理它的语法,请注意“:”字符的含义如何变化。 有一段时间它表示你正在指定继承,另一方面它指定了一个方法的访问修饰符,在第三位它只是命名空间限定符。 好吧,如果你很聪明,可以丢弃第三个,并注意到它实际上是'::'符号,而不仅仅是':'字符。
此外,关键字的含义可能会改变:
namespace Example class Foo : public Bar public : std::string myMethod() return "Oh noes!";
^^^^^^ ^^^^^^
首先,它为继承的基类定义访问修饰符,在第二个位置为方法定义访问修饰符。 更重要的是,首先它并不意味着后面跟着一个“:”而在第二个地方它必须跟着它!
如此多的规则,例外和极端情况,我们只涉及两个简单的事情:公共和':'。 现在,想象一下你要指定整个语言的语法。 您可以按照自己喜欢的方式描述所有内容。 但是,当你将所有规则收集在一起时,它们在某些时候可能会重叠并相互碰撞。 添加第N个规则后,您的“编译器”可能无法判断'public'是否实际上标记了继承,或者启动了一个方法:
namespace Example class Foo : public ::Bar public : std::string myMethod() return "Oh noes!";
^^^^^^^^ ^^^^^^^^
请注意,我只将Bar
更改为::Bar
。 我只添加了一个命名空间限定符,现在我们的规则“public is after a colon”被删除了。 由于我现在添加了一个“基类名称可能具有命名空间限定符”的规则,我还必须添加更多规则来涵盖另一个极端情况 - 在这个地方消除“public”和“:”含义的模糊性。
减少冗长的话题:规则越多,问题越多。 “编译器”增长,变慢,占用更多资源。 这导致无法处理大型代码文件,或者当用户必须等待那么长时间才能编译该模块时,会导致无法处理。
但对于用户来说更糟糕的是,更复杂或更模糊, 错误消息更糟糕 。 没有人想使用无法解析某些代码的编译器,也无法告诉你它有什么问题。
记住在C ++中,当你忘记一些';'时会发生什么? 在.h
文件中? 或者当你忘记一些}
? 编译器报告错误30或300行更远。 这是因为';' 并且'{}'可以在很多地方被省略,对于30或300行,编译器根本就不知道这是错的! 如果在任何地方都需要括号,可以更快地确定错误点。
另一种方法:在命名空间,类或函数级别使它们可选,将删除基本的块启动/块结束标记,并且至少:
任何人都不想要的任何部分。
C ++语法非常复杂,实际上根本不可能省略那些地方的大括号。 对于Java或普通的C,我认为可以创建一个不需要它们的语法/编译器,但是它仍然会损害错误报告。 特别是在允许使用#include
和宏的C中。 在早期的Java中,影响可能会更小,因为语法相对简单,比较当前的C ++。
可能最简单,最快速,最容易实现,也许最容易学习的语法......需要几乎无处不在的大括号(或任何其他分隔符)。 例如,检查LISP。 但是,你的大部分工作将包括不断编写相同的必需标记,许多语言用户根本不喜欢(即当我需要使用VisualBasic中的一些旧代码时,我会感到恶心“如果那么结束if “哎呀”
现在,如果你看一下像Python这样的无支撑语言 - 他们如何解决它? 它们通过......意图来表示块开始/块结束。 在这种语言中, 您必须正确缩进代码。 如果你没有正确地缩进它,它根本就不会编译,或者循环/函数/等会默默地让它们的代码弄乱,因为编译器不会知道哪个部分属于哪个范围。 这里再没有免费午餐。
基本上,方法(函数)是一组语句,它们组合在一起以执行操作。 我们将语句分组为可重用的。 也就是说,如果您知道在这种情况下将经常使用一组指令,我们将其创建为单独的函数。
如果您可以在一行代码中执行任务,那么为什么需要编写函数?
没有理由在编译器中添加额外的解析代码,因为功能实际上没用,你编写了多少个不是访问器或更改器的行方法? 这已在C#中通过属性处理,但尚未在Java中处理。
所以原因是,考虑到大多数开发人员不鼓励忽略可选的支架块,因此不太可能使用它。
因为语言的语法不允许你这样做。
以下是取自ISO / IEC 9899-1999规范的C函数的语法:
6.9.1 Function definitions
Syntax
1 function-definition:
declaration-specifiers declarator declaration-listopt compound-statement
复合语句部分是函数的主体,复合语句声明为
compound-statement:
{ block-item-listopt }
即它以大括号开始和结束。
if
, while
或类似的主体可以将statement
作为其正文。
(6.8.5) iteration-statement:
while ( expression ) statement
声明可以是几种结构之一。
statement:
labeled-statement
compound-statement
expression-statement
selection-statement
iteration-statement
jump-statement
其中只有compound-statement
需要大括号。
你无法准确地说C#中没有一个语句函数。 匿名方法可能就是其中之一。 如果没有单行语句,我们就无法在c#中使用Lambda表达式。 C#3.0不存在。
在c ++中,你需要一个复合语句来创建一个函数体 - 它实际上是用花键围绕的。 这并不意味着你需要立即拥有花括号,下面将编译得很好:
int foobar()
try {
return 1;
}
catch (...){return 0;}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.