簡體   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