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