語句
C 和 C++ 程序員將發現 D 的語句非常熟悉,他們還會發現有一些有趣的補充。語句: 標號語句 語句塊 表達式語句 聲明語句 If語句 調試語句 Version語句 While語句 DoWhile語句 For語句 Foreach語句 Switch語句 Case語句 Default語句 Continue語句 Break語句 Return語句 Goto語句 With語句 Synchronize語句 Try語句 Throw語句 Volatile語句 Asm語句 Pragma語句
Statement: LabeledStatement BlockStatement ExpressionStatement DeclarationStatement IfStatement DebugStatement VersionStatement WhileStatement DoWhileStatement ForStatement ForeachStatement SwitchStatement CaseStatement DefaultStatement ContinueStatement BreakStatement ReturnStatement GotoStatement WithStatement SynchronizeStatement TryStatement ThrowStatement VolatileStatement AsmStatement PragmaStatement
標號語句
語句可以有標號。標號是一種標誌符,其後跟隨一條語句。標號語句: 標誌符 ':' 語句
LabelledStatement: Identifier ':' Statement包括空語句在內的任何語句都可以有標號,因此都可以作爲 goto 語句的目標。標號語句也可以用作 break 或者 continue 語句的目標。
標號位於獨立的名字空間中,不與聲明、變量、類型等位於同一名字空間。就算如此,標號也不能同局部聲明重名。標號的名字空間是它們所在的函數體。標號的名字空間不嵌套,也就是說,一個語句塊中的標號可以在語句塊外訪問。
語句塊
語句塊是由{ }包括起來的語句序列。其中的語句按照詞法順序執行。語句塊: { } { 語句列表 } 語句列表: 語句 語句 語句列表
BlockStatement: { } { StatementList } StatementList: Statement Statement StatementList語句塊爲局部符號引入了新的作用域。儘管如此,在函數內部,局部符號的名稱必須唯一。
func1( x) { x; } func2() { x; { x; } } func3() { { x; } { x; } } func4() { { x; } { x++; } }主要的思想是避免在複雜函數內由於作用域聲明而錯誤的覆蓋了前面的名稱造成 bug 。函數內部的所有名稱都必須唯一。
表達式語句
表達式將被計算。表達式語句: 表達式 ;
ExpressionStatement: Expression ;沒有作用的表達式,如 (x + x),在表達式語句中是非法的。
聲明語句
聲明語句聲明並初始化變量。聲明語句: 類型 標誌符列表 ; 標誌符列表: 變量 變量 , 標誌符列表 變量: 標誌符 標誌符 = 賦值表達式
DeclarationStatement: Type IdentifierList ; IdentifierList: Variable Variable , IdentifierList Variable: Identifier Identifier = AssignmentExpression如果沒有指明 賦值表達式 來初始化變量,變量將被初始化爲它的默認值。
If 語句
If 語句提供了按條件執行語句的方法。If語句: if ( 表達式 ) 語句 if ( 表達式 ) 語句 else 語句表達式 將被計算,計算的結果必須可以被轉換爲布爾型。如果爲 true 執行 if 之後的語句,否則執行 else 之後的語句。
所謂的‘懸掛 else’問題可以通過鄰近匹配原則解決。
While 語句
While 語句實現了簡單的循環結構。While語句: while ( 表達式 ) 語句
WhileStatement: while ( Expression ) Statement表達式 將被計算,計算的結果必須可以被轉換爲布爾型。如果爲 true 執行 語句 。在 語句 被執行後,將再次計算 表達式 ,如果爲 true 則再次執行執行 語句 。持續這個過程直到 表達式 結果爲 false 。
break 語句將退出循環。continue 語句將直接跳轉到下一次計算 表達式 。
Do-While 語句
Do-While 語句實現了簡單的循環結構。Do語句: do 語句 while ( 表達式 )
DoStatement: do Statement while ( Expression )表達式 首先被執行。然後計算 表達式 ,結果必須可以被轉換爲布爾型。如果結果爲 true 繼續循環,直到 表達式 的值變爲 false 。
break 語句將推出循環。continue 語句將直接進行下一輪 表達式 估值。
For 語句
For 語句實現了帶有初始化、測試和遞增的循環結構。For語句: for (初始化; 測試; 遞增) 語句 初始化: 空 表達式 聲明 測試: 空 表達式 遞增: 空 表達式
ForStatement: for (Initialize; Test; Increment) Statement Initialize: empty Expression Declaration Test: empty Expression Increment: empty Expression先執行 初始化 。然後計算 測試 ,結果必須可以被轉換爲布爾型。如果結果爲 true ,執行 語句 。在執行 語句 後,將執行 遞增 。然後再次計算 測試 ,如果結果爲 true 再次執行 語句 。持續這個過程直到 測試 的計算結果爲 false 。
break 語句將推出循環。continue 語句將直接跳轉到 遞增 。
如果 初始值 聲明瞭一個變量,變量的作用域持續到 語句 結束。例如:
( i = 0; i < 10; i++) foo(i);等價於:
{ i; (i = 0; i < 10; i++) foo(i); }函數體不能爲空:
( i = 0; i < 10; i++) ;正確的寫法是:
( i = 0; i < 10; i++) { }初始值 可以忽略。測試 也可以被忽略,如果忽略,就假定爲 true 。
Foreach 語句
foreach 語句遍歷一個聚集的全部內容。Foreach語句: foreach (Foreach類型列表; 表達式) 語句 Foreach類型列表: Foreach類型 Foreach類型 , Foreach類型列表 Foreach類型: inout 類型 標誌符 類型 標誌符
ForeachStatement: foreach (ForeachTypeList; Expression) Statement ForeachTypeList: ForeachType ForeachType , ForeachTypeList ForeachType: inout Type Identifier Type Identifier先計算 表達式 的值。它的結果必須爲靜態數組、動態數組、關聯數組、結構或類類型的聚集表達式。對於聚集表達式的每個元素執行一次 語句 。在每次遍歷開始時,Foreach類型列表 聲明的變量默認爲聚集的內容的拷貝(即採用傳值方式)。如果變量是 inout 的,這些變量就是聚集內容的引用(即採用傳引用方式)。
如果聚集表達式是靜態或動態數組,可以聲明一個或者兩個變量。如果聲明瞭一個變量,那麼這個變量就被賦予數組元素的 值 ,一個接一個。變量的類型必須同數組內容的類型匹配,除了下面提到的特殊情況以外。如果聲明瞭兩個變量,第一個變量對應於 索引 ,第二個對應於 值 。索引 必須是 int 或者 uint 類型,它不能是 inout 的,它的值是數組元素的索引。
[] a; ... ( i, c; a) { printf(, i, c); }如果聚集表達式是 char、wchar 或者 dchar 的靜態或動態數組,則 值 的 類型 可以是 char、wchar 或 dchar 中的任何一個。採用這種方式,任何 UTF 數組可以被解碼爲任何 UTF 類型:
[] a = ; ( c; a) { printf(, c); } [] b = ; ( c; b) { printf(, c); }如果聚集表達式是關聯數組,可以聲明一個或者兩個變量。如果聲明瞭一個變量,那麼這個變量就被賦予數組元素的 值 ,一個接一個。變量的類型必須同數組內容的類型匹配。如果聲明瞭兩個變量,第一個變量對應於 索引 ,第二個對應於 值 。索引 必須同關聯數組的索引具有相同的類型,它不能是 inout ,它的值是數組元素的索引。
[[]] a; ... ([] s, d; a) { printf(, s, d); }如果聚集表達式是一個靜態或者動態數組,將從索引 0 到 數組的最大索引 遍歷數組元素。如果是關聯數組,則元素的順序是未定義的。如果是一個結構或者一個類對象,訪問的順序由它們的 opApply 成員函數定義。
如果聚集是一個結構或者類對象,則它必須定義具有如下類型的 opApply 函數:
opApply( ( Type [, ...]) dg);其中 Type 要同 foreach 聲明中 標誌符 中的 類型 匹配。傳遞給 opApply 的委託類型中剩下的那些 類型 (上式中的“...”)對應於其餘的多個 Foreach類型 。結構或類中可以有多個不同的 opApply 函數,foreach語句 會使用類型匹配的函數,該函數的參數 dg 的參數類型要同 foreach語句 中對應的 Foreach類型 匹配。opApply 的函數體遍歷聚集的元素,並將它們作爲參數依次傳遞給 dg 函數。如果 dg 返回 0 ,則 opApply 繼續應用於下一個元素。如果 dg 返回一個非零值,opApply 必須停止遍歷並返回那個值。如果 opApply 順利遍歷了所有的元素,會返回 0 。
例如,考慮包含兩個元素的容器類:
Foo { array[2]; opApply( ( ) dg) { result = 0; ( i = 0; i < array.length; i++) { result = dg(array[i]); if (result) ; } result; } }一個可能的例子是:
test() { Foo a = Foo(); a.array[0] = 73; a.array[1] = 82; ( u; a) { printf(, u); } }將打印出:
73 82聚集可以是字符串文字量,這樣的聚集可以看作 char、wchar 或 dchar 數組來訪問:
test() { ( c; ) { printf(, c); } ( w; ) { wprintf(, w); } }將打印出:
'a' 'b' 'x' 'y'inout 用來更新數據項:
test() { [2] a = [7, 8]; ( u; a) { u++; } ( u; a) { printf(, u); } }將打印出:
8 9在 foreach 遍歷所有數據項時,不能修改聚集本身,不能重新設定聚集大小、重新分配、釋放、重新賦值或析構。
[] a; [] b; ( i; a) { a = ; a.length += 10; a = b; } a = ;如果在 foreach 體內有 Break語句 ,則會退出 foreach ,而 Continue語句 將立即開始下一輪遍歷。