跳至內容

Ada 程式設計/控制

來自華夏公益教科書

Ada. Time-tested, safe and secure.
Ada. 經時間考驗,安全可靠。
這篇文章關於計算機程式設計,提供虛擬碼Adaooc版本。

條件語句

[編輯原始碼]

條件語句是隻有當特定表示式(條件)為時才會執行的程式碼塊。

if-else 語句是最簡單的條件語句。它們也被稱為分支,因為當程式在執行過程中到達一個 if 語句時,控制會“分支”到兩個或多個“方向”中的一個。if-else 語句通常具有以下形式


if condition then
    statement;
else
    other statement;
end if;

如果原始條件滿足,則第一個語句中的所有程式碼都將被執行。可選的 else 部分指定一個備用語句,該語句將在條件為假時執行。不同程式語言的語法會有所不同,但大多數程式語言(特別是過程式結構化 語言)都內建了某種形式的 if-else 條件語句。if-else 語句通常可以擴充套件為以下形式


if condition then
    statement;
elsif condition then
    other statement;
elsif condition then
    other statement;
...
else
    another statement;
end if; 

整個程式碼塊中只執行一個語句。這個語句將是第一個其條件計算結果為真的語句。使用示例可以更容易理解 if-else-if 結構的概念


with Ada.Text_IO;
use  Ada.Text_IO;
...
type Degrees is new Float range -273.15 .. Float'Last;
...
Temperature : Degrees;
...
if Temperature >= 40.0 then
    Put_Line ("Wow!");
    Put_Line ("It's extremely hot");
elsif Temperature >= 30.0 then
    Put_Line ("It's hot");
elsif Temperature >= 20.0 then
    Put_Line ("It's warm");
elsif Temperature >= 10.0 then
    Put_Line ("It's cool");
elsif Temperature >= 0.0 then
    Put_Line ("It's cold");
else
    Put_Line ("It's freezing");
end if; 

最佳化提示

[編輯原始碼]

當此程式執行時,計算機將按順序檢查所有條件,直到其中一個條件與其對真的概念匹配。一旦發生這種情況,程式將執行緊隨條件之後的語句並繼續,而不會檢查任何其他條件。出於這個原因,當您嘗試最佳化 程式時,最好按降序機率對 if-else 條件進行排序。這將確保在最常見的情況下,計算機需要做更少的工作,因為它很可能只需要檢查一兩個“分支”就能找到它應該執行的語句。但是,在第一次編寫程式時,儘量不要過多地考慮這個問題,以免您發現自己進行了過早最佳化

話雖如此,您應該知道,一個最佳化編譯器可能會隨意重新排列您的 if 語句,前提是該語句沒有副作用。在其他技術中,最佳化編譯器甚至可能應用跳轉表二分搜尋


在 Ada 中,預設情況下,具有多個條件的條件語句不使用短路求值。為了模擬 C/C++ 的短路求值,在條件之間使用and thenor else

通常需要將一個特定變數與幾個常量表達式進行比較。對於這種條件表示式,存在 case 語句。例如


case X is
   when 1 =>

      Walk_The_Dog;

   when 5 =>

      Launch_Nuke;

   when 8 | 10 =>

      Sell_All_Stock;

   when others =>

      Self_Destruct;

end case;

X 的子型別必須是離散型別,即列舉型別或整數型別。

在 Ada 中,case 語句的一個優點是編譯器將檢查選擇的覆蓋率,即變數 X 的子型別的所有值都必須存在,或者存在一個預設分支when others 必須指定在其餘情況下該怎麼做。

無條件語句

[編輯原始碼]

無條件語句允許您更改程式的流程,而無需條件。使用無條件語句時要小心。它們通常會使程式難以理解。閱讀goto 有害嗎? 獲取更多資訊。

結束一個函式並返回到呼叫過程或函式。


對於過程

return;

對於函式

return Value;

Goto 將控制權轉移到標籤之後的語句。


   goto Label;

   Dont_Do_Something;

<<Label>>
   ...

goto 有害嗎?

[編輯原始碼]

自從迪克斯特拉教授發表了Go To Statement Considered Harmfulgoto 在結構化程式語言中被認為是不好的做法,實際上,許多程式設計風格指南禁止使用 goto 語句。但人們經常忽略的是,任何不是過程或函式中最後一個語句的 return 也是一個無條件語句——一個偽裝的 goto。不過,有一個重要的區別:return 是一種僅向前使用的 goto。異常也是一種 goto 語句;請注意,它們不需要指定將要跳轉到的位置。

因此,如果您有包含多個 return 語句的函式和過程,那麼您就像使用 goto 一樣破壞了程式的結構。實際上,幾乎每個程式設計師都熟悉 'return' 語句及其關聯的行為;因此,在可讀性方面,以下兩個示例幾乎相同


還要注意,Ada 中的 goto 語句比其他語言中的更安全,因為它不允許您將控制權轉移

  • 到程式碼塊之外;
  • case 語句、if 語句或 select 語句的備選方案之間;
  • 在不同的異常處理程式之間;或者從處理的語句序列的異常處理程式返回到其語句序列。
procedure Use_Return is
begin
   Do_Something;

   if Test then
      return;
   end if;

   Do_Something_Else;

   return;
end Use_Return;
procedure Use_Goto is
begin
   Do_Something;
  
   if Test then
      goto Exit_Use_Goto;
   end if;

   Do_Something_Else;

<<Exit_Use_Goto>>
   return;
end Use_Goto;

由於使用 goto 需要宣告一個標籤,因此 goto 實際上比使用 return 可讀性高兩倍。因此,如果您關注的是可讀性,而不是嚴格的“不要使用 goto”程式設計規則,那麼您應該使用 goto 而不是多個 return。當然,最好的方法是結構化方法,在這種方法中既不需要 goto 也不需要多個 return


procedure Use_If is
begin
   Do_Something;
  
   if not Test then

      Do_Something_Else;

   end if;

   return;
end Use_If;

迴圈允許您一遍又一遍地重複一組語句。

無限迴圈

[編輯原始碼]

無限迴圈是一個永不結束的迴圈,迴圈內的語句會永遠重複。術語“無限迴圈”是一個相對術語;如果正在執行的程式因程式控制範圍之外的某些原因而強制終止,則無限迴圈確實會結束。


Endless_Loop :
   loop

      Do_Something;

   end loop Endless_Loop;

迴圈名稱(在本例中為“Endless_Loop”)是 Ada 的一個可選功能。命名迴圈對於可讀性很好,但不是嚴格必需的。但是,如果程式應該跳出內部迴圈,迴圈名稱很有用,請參見下文。

迴圈條件在開頭

[編輯原始碼]

此迴圈在開頭有一個條件。只要條件滿足,語句就會重複執行。如果條件在一開始就不滿足,則迴圈內的語句永遠不會被執行。


While_Loop :
   while X <= 5 loop

      X := Calculate_Something;

   end loop While_Loop;

迴圈條件在結尾

[編輯原始碼]

此迴圈在結尾有一個條件,語句會重複執行,直到條件滿足。由於檢查在結尾,因此語句至少執行一次。


Until_Loop :
   loop

      X := Calculate_Something;

      exit Until_Loop when X > 5;
   end loop Until_Loop;

迴圈條件在中間

[編輯原始碼]

有時你需要先進行計算,並在滿足特定條件時退出迴圈。但如果條件不滿足,則需要執行其他操作。因此你需要一個退出條件位於中間的迴圈。


Exit_Loop :
   loop

      X := Calculate_Something;

      exit Exit_Loop when X > 5;

      Do_Something (X);

   end loop  Exit_Loop;

在 Ada 中,exit 條件可以與任何其他迴圈語句結合使用。你也可以擁有多個 exit 語句。你也可以在多個迴圈巢狀的情況下,退出命名為外層迴圈。

for 迴圈

[編輯原始碼]

很多時候,你需要一個迴圈,其中一個特定變數從給定的起始值向上或向下計數到特定結束值。你可以在此處使用 while 迴圈——但由於這是一種非常常見的迴圈,因此提供了一種更簡單的語法。


For_Loop :
   for I in Integer range 1 .. 10 loop

      Do_Something (I)

   end loop For_Loop;

你不必像示例中那樣宣告子型別和範圍。如果你省略子型別,則編譯器將根據上下文確定它;如果你省略範圍,則迴圈將遍歷給定子型別的每個值。

與 Ada 一樣,當“根據上下文確定”給出兩個或多個可能的選項時,將顯示錯誤訊息,然後你必須指定要使用的型別。Ada 僅在安全的情況下進行“猜測”。

迴圈計數器 I 是一個隱式宣告的常量,在迴圈體結束後將不再存在。

陣列上的 for 迴圈

[編輯原始碼]

另一種非常常見的情況是需要一個迴圈來遍歷陣列的每個元素。以下示例程式碼展示瞭如何實現這一點。


Array_Loop :
   for I in X'Range loop

      X (I) := Get_Next_Element;

   end loop Array_Loop;

其中 X 是一個數組。注意:這種語法主要用於陣列(因此得名),但也可以在需要完整迭代的其他型別上使用。

工作示例

[編輯 | 編輯原始碼]

以下示例展示瞭如何遍歷整數型別的每個元素。

檔案: range_1.adb (檢視, 純文字, 下載頁面, 瀏覽所有)
with Ada.Text_IO;

procedure Range_1 is
   type Range_Type is range -5 .. 10;

   package T_IO renames Ada.Text_IO;
   package I_IO is new  Ada.Text_IO.Integer_IO (Range_Type);

begin
   for A in Range_Type loop
      I_IO.Put (Item  => A,
                Width => 3,
                Base  => 10);

      if A < Range_Type'Last then
         T_IO.Put (",");
      else
         T_IO.New_Line;
      end if;
   end loop;
end Range_1;

另請參閱

[編輯 | 編輯原始碼]

華夏公益教科書

[編輯 | 編輯原始碼]

Ada 參考手冊

[編輯 | 編輯原始碼]
華夏公益教科書