跳轉到內容

Ada 程式設計/基礎

來自華夏公益教科書,為開放世界提供開放書籍

Ada. Time-tested, safe and secure.
Ada. 經久耐用、安全可靠。

"Hello, world!" 程式

[編輯 | 編輯原始碼]

"Hello, world!"

[編輯 | 編輯原始碼]

語言的 語法 的一個常見示例是 Hello world 程式。這是一個簡單的 Ada 實現

檔案:hello_world_1.adb,Crate:basic (檢視, 純文字, 使用 Alire 下載, Alire 包資訊)
with Ada.Text_IO;

procedure Hello is
begin
   Ada.Text_IO.Put_Line("Hello, world!");
end Hello;

with 語句將包 Ada.Text_IO 新增到程式中。此包包含在每個 Ada 編譯器中,幷包含文字輸入/輸出所需的所有功能。with 語句使 Ada.Text_IO 的宣告可供過程 Hello 使用。這包括在 Ada.Text_IO 中宣告的型別、Ada.Text_IO 的子程式以及 Ada.Text_IO 中為公開使用而宣告的所有其他內容。在 Ada 中,包可以用作工具箱。Text_IO 為在一個易於訪問的模組中進行文字輸入和輸出提供了一組工具。以下是包 Ada.Text_IO 的部分概述

package Ada.Text_IO is

   type File_Type is limited private;

   --  more stuff

   procedure Open(File : in out File_Type;
                  Mode : File_Mode;
                  Name : String;
                  Form : String := "");

   --  more stuff

   procedure Put_Line (Item : String);

   --  more stuff

end Ada.Text_IO;

接下來在程式中我們宣告一個主過程。Ada 主過程不需要被命名為 "main"。任何簡單的名稱都可以,這裡就是 Hello。編譯器可能允許將過程或函式用作主子程式。 [1]

Ada.Text_IO.Put_Line 的呼叫將文字 "Hello World" 寫入當前輸出檔案。

with 子句使包的內容 透過選擇可見:我們需要用其完整包名 Ada.Text_IOText_IO 包中的過程名 Put_Line 新增字首。如果你需要更頻繁地使用包中的過程,則需要某種捷徑。有兩個選擇

"Hello, world!" 帶重新命名

[編輯 | 編輯原始碼]

透過重新命名包,可以為任何包名提供一個更短的別名。[2] 這減少了打字量,同時保留了一些可讀性。

檔案:hello_world_2.adb,Crate:basic (檢視, 純文字, 使用 Alire 下載, Alire 包資訊)
with Ada.Text_IO;

procedure Hello is
   package IO renames Ada.Text_IO;
begin
   IO.Put_Line("Hello, world!");
   IO.New_Line;
   IO.Put_Line("I am an Ada program with package rename.");
end Hello;

"Hello, world!" 帶本地使用

[編輯 | 編輯原始碼]

Theuse 子句使包的所有內容對宣告它的作用域直接可見。use 可以放在本地或全域性(見下文)。與重新命名一樣,這減少了打字量,同時保留了一些可讀性。

檔案:hello_world_3.adb,Crate:basic (檢視, 純文字, 使用 Alire 下載, Alire 包資訊)
with Ada.Text_IO;

procedure Hello is
   use Ada.Text_IO;   
begin
   Put_Line("Hello, world!");
   New_Line;
   Put_Line("I am an Ada program with package use.");
end Hello;

use 可以用於包,並以以下形式使用use type 用於型別。use type 僅使給定型別的 運算子 直接可見,但不包括型別上的任何其他操作。

"Hello, world!" 帶全域性使用

[編輯 | 編輯原始碼]

使用use 子句在任何作用域之外都會使包的所有內容對整個編譯單元直接可見。它允許更少的打字,但會降低可讀性,並可能導致名稱衝突。

檔案:hello_world_4.adb,Crate:basic (檢視, 純文字, 使用 Alire 下載, Alire 包資訊)
with Ada.Text_IO;
use Ada.Text_IO;

procedure Hello is    
begin
   Put_Line("Hello, world!");
   New_Line;
   Put_Line("I am an Ada program with package use.");
end Hello;

有了這麼多選擇,需要考慮在什麼情況下使用哪個選擇。一個建議的“經驗法則”

  • 全域性use 用於最常用的包(s)
  • renames 用於大多數其他包(s)
  • 本地use 用於僅在一個過程中使用的包
  • 不使用userenames 用於僅使用一次的包(s)

你可能還有更簡單的規則(例如,始終useAda 及其子包,永不use 任何其他內容)。

Ada 開發早期另一個規則是全域性use 用於所有包,除非發生名稱衝突。

編譯 "Hello, world!" 程式

[編輯 | 編輯原始碼]

有關如何在各種編譯器上構建“Hello, world!”程式的資訊,請參閱構建章節。

常見問題解答:為什麼“Hello, world!”如此之大?

[編輯 | 編輯原始碼]

Ada 初學者經常會問,像“Hello, world!”這樣簡單的程式怎麼會產生這麼大的可執行檔案。原因與 Ada 無關,通常可以在使用的編譯器和連結器選項中找到 - 或者更確切地說,是未使用的選項。

Ada 編譯器 - 或者一般來說好的編譯器 - 的標準行為不是建立最佳程式碼,而是為了易用性而最佳化。這樣做是為了確保一個“開箱即用”的系統,從而不會因不必要的複雜性而嚇跑潛在的新使用者。

您可以在下載示例程式的同時下載的 GNAT 專案檔案,使用更最佳化的編譯器、繫結器和連結器選項。如果您使用這些選項,“Hello, world!”將變得小很多。

 32K ./Linux-i686-Debug/hello_world_1
8.0K ./Linux-i686-Release/hello_world_1
 36K ./Linux-x86_64-Debug/hello_world_1
 12K ./Linux-x86_64-Release/hello_world_1
1.1M ./Windows_NT-i686-Debug/hello_world_1.exe
 16K ./Windows_NT-i686-Release/hello_world_1.exe
 32K ./VMS-AXP-Debug/hello_world_1.exe
 12K ./VMS-AXP-Release/hello_world_1.exe

為了比較,一個簡單的 gnat make 編譯的大小

497K hello_world_1 (Linux i686)
500K hello_world_1 (Linux x86_64)
1.5M hello_world_1.exe (Windows_NT i686)
589K hello_world_1.exe (VMS AXP)

值得一提的是,使用 GNAT/MSVC 7.1/GCC(C) 編譯的 hello_world(Ada、C、C++)在給定可比的最佳化和連結器方法的情況下,都產生大小大致相同的可執行檔案。

需要注意的事項

[編輯 | 編輯原始碼]

準備好識別 Ada 的一些重要特性,這些特性對於學習其語法和語義至關重要,將會有所幫助。

梳狀格式

[編輯 | 編輯原始碼]

在所有控制結構和模組結構中都存在一種梳狀格式。請參閱以下示例以瞭解梳狀格式。您不必理解這些示例的作用 - 只需查詢佈局中的相似之處即可。

if Boolean expression then
   statements
elsif Boolean expression then
   statements
else
   statements
end if;
while Boolean expression loop
   statements
end loop;
for variable in range loop
   statements
end loop;
declare
   declarations
begin
   statements
exception
   handlers
end;
procedure P (parameters : in out type) is
   declarations
begin
   statements
exception
   handlers
end P;
function F (parameters : in type) return type is
   declarations
begin
   statements
exception
   handlers
end F;
package P is
   declarations
private
   declarations
end P;
generic
   declarations
package P is
   declarations
private
   declarations
end P;
generic
   declarations
procedure P (parameters : in out type);

請注意,分號始終用於終止語句和宣告;空行(或單獨的分號)不是有效的語句:空語句是

null;

型別和子型別

[編輯 | 編輯原始碼]

型別子型別之間存在重要的區別:型別由一組值及其操作給出。子型別由型別和一個約束給出,該約束限制了值集。值始終屬於一種型別。物件(常量和變數)屬於子型別。這概括、澄清並系統化了一種關係,例如Integer 和 1..100 之間的關係,這種關係在Pascal 的語義中是特殊處理的。

約束型別和無約束型別

[編輯 | 編輯原始碼]

約束型別和無約束型別之間存在重要的區別。無約束型別具有一種或多種自由引數,這些引數會影響其大小或形狀。約束型別固定了這些引數的值,因此確定了其大小和形狀。簡單來說,物件必須屬於約束型別,但形式引數可以是無約束型別(它們採用任何相應實際引數的約束)。這解決了 Pascal 中陣列引數的問題(以及其他問題)。

動態型別

[編輯 | 編輯原始碼]

PascalC 中的值必須是靜態的(例如,陣列的下標邊界),但在 Ada 中它們可以是動態的。但是,在動態求值無法允許合理實現的某些情況下(例如,在設定浮點型別的精度位數時),需要靜態表示式。

關注點分離

[編輯 | 編輯原始碼]

Ada 一直支援介面和機制的分離。您可以在的格式中看到這一點,它將包的宣告與其主體分開;以及在私有型別的概念中,其在 Ada 資料結構方面的表示在包含其定義的作用域之外是不可訪問的。

在哪裡尋求幫助

[編輯 | 編輯原始碼]

大多數 Ada 專家潛伏在Usenet 新聞組 comp.lang.ada(英語)和fr.comp.lang.ada(法語)中;可以使用新聞閱讀器或透過眾多網路介面中的一個來訪問它們。這是所有與 Ada 相關問題的地方。

這些新聞組中的人願意提供幫助,但不會為學生完成作業;他們不會發布作業的完整答案。相反,他們會為學生提供指導,讓他們自己找到答案。

有關更多線上資源,請參閱本華夏公益教科書介紹中的外部連結部分。

  1. 主子程式甚至可以有引數;哪些子程式可以用作主子程式是實現定義的。參考手冊在10.2: LRM 10.2(29) [註釋]中解釋了詳細資訊:“……,實現需要支援所有作為公共無引數庫過程的主子程式。” 表示未巢狀在另一個子程式中,例如,以及現在我們不必關心的其他事情。
  2. renames 也可以用於過程、函式、變數、陣列元素。它不能用於型別 - 型別重新命名可以使用subtype 完成。
華夏公益教科書