Ada 程式設計/控制
條件語句
[編輯原始碼]條件語句是隻有當特定表示式(條件)為真時才會執行的程式碼塊。
if-else
[編輯原始碼]if-else 語句是最簡單的條件語句。它們也被稱為分支,因為當程式在執行過程中到達一個 if 語句時,控制會“分支”到兩個或多個“方向”中的一個。if-else 語句通常具有以下形式
ifconditionthenstatement;elseother statement;endif;
如果原始條件滿足,則第一個語句中的所有程式碼都將被執行。可選的 else 部分指定一個備用語句,該語句將在條件為假時執行。不同程式語言的語法會有所不同,但大多數程式語言(特別是過程式 和結構化 語言)都內建了某種形式的 if-else 條件語句。if-else 語句通常可以擴充套件為以下形式
ifconditionthenstatement;elsifconditionthenother statement;elsifconditionthenother statement; ...elseanother statement;endif;
整個程式碼塊中只執行一個語句。這個語句將是第一個其條件計算結果為真的語句。使用示例可以更容易理解 if-else-if 結構的概念
withAda.Text_IO;useAda.Text_IO; ...typeDegreesisnewFloatrange-273.15 .. Float'Last; ... Temperature : Degrees; ...ifTemperature >= 40.0thenPut_Line ("Wow!"); Put_Line ("It's extremely hot");elsifTemperature >= 30.0thenPut_Line ("It's hot");elsifTemperature >= 20.0thenPut_Line ("It's warm");elsifTemperature >= 10.0thenPut_Line ("It's cool");elsifTemperature >= 0.0thenPut_Line ("It's cold");elsePut_Line ("It's freezing");endif;
最佳化提示
[編輯原始碼]當此程式執行時,計算機將按順序檢查所有條件,直到其中一個條件與其對真的概念匹配。一旦發生這種情況,程式將執行緊隨條件之後的語句並繼續,而不會檢查任何其他條件。出於這個原因,當您嘗試最佳化 程式時,最好按降序機率對 if-else 條件進行排序。這將確保在最常見的情況下,計算機需要做更少的工作,因為它很可能只需要檢查一兩個“分支”就能找到它應該執行的語句。但是,在第一次編寫程式時,儘量不要過多地考慮這個問題,以免您發現自己進行了過早最佳化。
話雖如此,您應該知道,一個最佳化編譯器可能會隨意重新排列您的 if 語句,前提是該語句沒有副作用。在其他技術中,最佳化編譯器甚至可能應用跳轉表 和二分搜尋。
在 Ada 中,預設情況下,具有多個條件的條件語句不使用短路求值。為了模擬 C/C++ 的短路求值,在條件之間使用 或and then。or else
case
[編輯原始碼]通常需要將一個特定變數與幾個常量表達式進行比較。對於這種條件表示式,存在 case 語句。例如
caseXiswhen1 => Walk_The_Dog;when5 => Launch_Nuke;when8 | 10 => Sell_All_Stock;whenothers=> Self_Destruct;endcase;
X 的子型別必須是離散型別,即列舉型別或整數型別。
在 Ada 中,case 語句的一個優點是編譯器將檢查選擇的覆蓋率,即變數 X 的子型別的所有值都必須存在,或者存在一個預設分支when others 必須指定在其餘情況下該怎麼做。
無條件語句
[編輯原始碼]無條件語句允許您更改程式的流程,而無需條件。使用無條件語句時要小心。它們通常會使程式難以理解。閱讀goto 有害嗎? 獲取更多資訊。
return
[編輯原始碼]結束一個函式並返回到呼叫過程或函式。
對於過程
return;
對於函式
return Value;
goto
[編輯原始碼]Goto 將控制權轉移到標籤之後的語句。
goto Label;
Dont_Do_Something;
<<Label>>
...
goto 有害嗎?
[編輯原始碼]自從迪克斯特拉教授發表了Go To Statement Considered Harmful,goto 在結構化程式語言中被認為是不好的做法,實際上,許多程式設計風格指南禁止使用 goto 語句。但人們經常忽略的是,任何不是過程或函式中最後一個語句的 return 也是一個無條件語句——一個偽裝的 goto。不過,有一個重要的區別:return 是一種僅向前使用的 goto。異常也是一種 goto 語句;請注意,它們不需要指定將要跳轉到的位置。
因此,如果您有包含多個 return 語句的函式和過程,那麼您就像使用 goto 一樣破壞了程式的結構。實際上,幾乎每個程式設計師都熟悉 'return' 語句及其關聯的行為;因此,在可讀性方面,以下兩個示例幾乎相同
還要注意,Ada 中的 goto 語句比其他語言中的更安全,因為它不允許您將控制權轉移
- 到程式碼塊之外;
- 在 case 語句、if 語句或 select 語句的備選方案之間;
- 在不同的異常處理程式之間;或者從處理的語句序列的異常處理程式返回到其語句序列。
procedureUse_ReturnisbeginDo_Something;ifTestthenreturn;endif; Do_Something_Else;return;endUse_Return;
procedureUse_GotoisbeginDo_Something;ifTestthengotoExit_Use_Goto;endif; Do_Something_Else; <<Exit_Use_Goto>>return;endUse_Goto;
由於使用 goto 需要宣告一個標籤,因此 goto 實際上比使用 return 可讀性高兩倍。因此,如果您關注的是可讀性,而不是嚴格的“不要使用 goto”程式設計規則,那麼您應該使用 goto 而不是多個 return。當然,最好的方法是結構化方法,在這種方法中既不需要 goto 也不需要多個 return
procedureUse_IfisbeginDo_Something;ifnotTestthenDo_Something_Else;endif;return;endUse_If;
迴圈
[編輯原始碼]迴圈允許您一遍又一遍地重複一組語句。
無限迴圈
[編輯原始碼]無限迴圈是一個永不結束的迴圈,迴圈內的語句會永遠重複。術語“無限迴圈”是一個相對術語;如果正在執行的程式因程式控制範圍之外的某些原因而強制終止,則無限迴圈確實會結束。
Endless_Loop :loopDo_Something;endloopEndless_Loop;
迴圈名稱(在本例中為“Endless_Loop”)是 Ada 的一個可選功能。命名迴圈對於可讀性很好,但不是嚴格必需的。但是,如果程式應該跳出內部迴圈,迴圈名稱很有用,請參見下文。
迴圈條件在開頭
[編輯原始碼]此迴圈在開頭有一個條件。只要條件滿足,語句就會重複執行。如果條件在一開始就不滿足,則迴圈內的語句永遠不會被執行。
While_Loop :whileX <= 5loopX := Calculate_Something;endloopWhile_Loop;
迴圈條件在結尾
[編輯原始碼]此迴圈在結尾有一個條件,語句會重複執行,直到條件滿足。由於檢查在結尾,因此語句至少執行一次。
Until_Loop :loopX := Calculate_Something;exitUntil_LoopwhenX > 5;endloopUntil_Loop;
迴圈條件在中間
[編輯原始碼]有時你需要先進行計算,並在滿足特定條件時退出迴圈。但如果條件不滿足,則需要執行其他操作。因此你需要一個退出條件位於中間的迴圈。
Exit_Loop :loopX := Calculate_Something;exitExit_LoopwhenX > 5; Do_Something (X);endloopExit_Loop;
在 Ada 中,exit 條件可以與任何其他迴圈語句結合使用。你也可以擁有多個 exit 語句。你也可以在多個迴圈巢狀的情況下,退出命名為外層迴圈。
for 迴圈
[編輯原始碼]很多時候,你需要一個迴圈,其中一個特定變數從給定的起始值向上或向下計數到特定結束值。你可以在此處使用 while 迴圈——但由於這是一種非常常見的迴圈,因此提供了一種更簡單的語法。
For_Loop :forIinIntegerrange1 .. 10loopDo_Something (I)endloopFor_Loop;
你不必像示例中那樣宣告子型別和範圍。如果你省略子型別,則編譯器將根據上下文確定它;如果你省略範圍,則迴圈將遍歷給定子型別的每個值。
與 Ada 一樣,當“根據上下文確定”給出兩個或多個可能的選項時,將顯示錯誤訊息,然後你必須指定要使用的型別。Ada 僅在安全的情況下進行“猜測”。
迴圈計數器 I 是一個隱式宣告的常量,在迴圈體結束後將不再存在。
陣列上的 for 迴圈
[編輯原始碼]另一種非常常見的情況是需要一個迴圈來遍歷陣列的每個元素。以下示例程式碼展示瞭如何實現這一點。
Array_Loop :forIinX'RangeloopX (I) := Get_Next_Element;endloopArray_Loop;
其中 X 是一個數組。注意:這種語法主要用於陣列(因此得名),但也可以在需要完整迭代的其他型別上使用。
以下示例展示瞭如何遍歷整數型別的每個元素。
withAda.Text_IO;procedureRange_1istypeRange_Typeisrange-5 .. 10;packageT_IOrenamesAda.Text_IO;packageI_IOisnewAda.Text_IO.Integer_IO (Range_Type);beginforAinRange_TypeloopI_IO.Put (Item => A, Width => 3, Base => 10);ifA < Range_Type'LastthenT_IO.Put (",");elseT_IO.New_Line;endif;endloop;endRange_1;
- 5.3: if 語句 [帶註釋的]
- 5.4: case 語句 [帶註釋的]
- 5.5: loop 語句 [帶註釋的]
- 5.6: 塊語句 [帶註釋的]
- 5.7: exit 語句 [帶註釋的]
- 5.8: goto 語句 [帶註釋的]
- 6.5: return 語句 [帶註釋的]
