繁体   English   中英

为什么不能在没有花括号的情况下创建1语句函数?

[英]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 }

即它以大括号开始和结束。

ifwhile或类似的主体可以将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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM