UNIT(モジュール)の基本
『Pascal』の UNIT は、関連する型・定数・変数・手続き・関数をひとまとめにしたモジュールです。INTERFACE セクションで外部に公開するシンボルを宣言し、IMPLEMENTATION セクションで実装を記述します。INITIALIZATION セクションを使うとプログラム起動時に自動実行されるコードを書けます。USES 節に UNIT 名を列挙するだけで再利用でき、大規模プログラムの分割管理に役立ちます。
構文
{ -----------------------------------------------
UNIT の基本構造
----------------------------------------------- }
unit ユニット名;
{ -----------------------------------------------
INTERFACE セクション — 外部に公開する宣言を書きます
----------------------------------------------- }
interface
uses
依存ユニット名1, 依存ユニット名2; { 他のユニットへの依存(省略可)}
const
公開定数名 = 値;
type
公開型名 = ...;
var
公開変数名 : 型;
{ 手続き・関数はヘッダーのみ宣言します(実装は IMPLEMENTATION に書く)}
procedure 公開手続き名(引数 : 型);
function 公開関数名(引数 : 型) : 戻り値の型;
{ -----------------------------------------------
IMPLEMENTATION セクション — 実装を記述します
----------------------------------------------- }
implementation
uses
実装専用の依存ユニット名; { INTERFACE に不要な依存はここに書きます }
{ 非公開の内部定数・変数・手続き・関数はここで定義します }
const
内部定数名 = 値;
procedure 公開手続き名(引数 : 型);
begin
{ 処理内容 }
end;
function 公開関数名(引数 : 型) : 戻り値の型;
begin
{ 処理内容 }
公開関数名 := 戻り値;
end;
{ -----------------------------------------------
INITIALIZATION セクション(省略可)
— プログラム起動時に一度だけ実行されます
----------------------------------------------- }
initialization
{ 初期化処理 }
{ -----------------------------------------------
FINALIZATION セクション(省略可)
— プログラム終了時に一度だけ実行されます
----------------------------------------------- }
finalization
{ 後片付け処理 }
end.
構文一覧
| 構文 / キーワード | 概要 |
|---|---|
unit ユニット名; | UNIT ファイルの先頭に書くキーワードです。ファイル名(拡張子なし)とユニット名を一致させる必要があります。 |
interface | 外部に公開するシンボル(型・定数・変数・手続き・関数のヘッダー)を宣言するセクションの開始です。 |
implementation | 手続き・関数の実装本体と、非公開の内部定義を記述するセクションの開始です。 |
initialization | プログラム起動時に一度だけ実行されるコードブロックです。省略できます。グローバル変数の初期化などに使います。 |
finalization | プログラム終了時に一度だけ実行されるコードブロックです。省略できます。リソースの解放などに使います。 |
uses ユニット名; | 依存する UNIT を宣言します。interface セクションと implementation セクションの両方に書けます。 |
| 公開と非公開 | interface に書いたシンボルが公開されます。implementation 内だけで定義したシンボルはそのユニット内専用の非公開となります。 |
| ファイル名の規則 | Free Pascal では UNIT 名をファイル名(小文字)に合わせる慣習があります(例: unit EvaUnit; → evaunit.pas)。 |
サンプルコード
eva_pilots.pas(UNIT ファイル)
{ eva_pilots.pas — エヴァンゲリオンのパイロット情報を管理する UNIT です }
{
このファイルは単体ではコンパイルしません。
メインプログラム eva_main.pas から uses で参照します。
}
unit eva_pilots;
{ -----------------------------------------------
INTERFACE セクション
— 外部(メインプログラム)に公開するシンボルを宣言します
----------------------------------------------- }
interface
{ パイロットのステータスを表す列挙型(公開)}
type
TPilotStatus = (
statusActive, { 現役パイロット }
statusInjured, { 負傷・休養中 }
statusMissing { 行方不明 }
);
{ パイロット 1 人分のデータを格納するレコード型(公開)}
TPilot = record
name : string[40]; { パイロット名 }
unit_number : Integer; { 搭乗 Eva 号機番号 }
sync_rate : Real; { シンクロ率(%)}
status : TPilotStatus;{ 現在のステータス }
end;
{ パイロット数の定数(公開)}
const
PILOT_COUNT = 5;
{ パイロット情報を表示する手続きのヘッダー(公開)}
procedure PrintPilot(const p : TPilot);
{ シンクロ率の平均を返す関数のヘッダー(公開)}
function AverageSyncRate(const pilots : array of TPilot) : Real;
{ -----------------------------------------------
IMPLEMENTATION セクション
— 手続き・関数の実装本体と、非公開の内部定義を記述します
----------------------------------------------- }
implementation
{ ステータスを文字列に変換する非公開ヘルパー関数
— interface に宣言していないため外部からは呼び出せません }
function StatusToStr(s : TPilotStatus) : string;
begin
case s of
statusActive : StatusToStr := 'Active';
statusInjured : StatusToStr := 'Injured';
statusMissing : StatusToStr := 'Missing';
end;
end;
{ PrintPilot の実装 — パイロット情報を整形して標準出力に書き出します }
procedure PrintPilot(const p : TPilot);
begin
WriteLn(' Unit-', p.unit_number, ' ', p.name);
Write (' Sync Rate : ');
WriteLn(p.sync_rate:0:1, '%');
WriteLn(' Status : ', StatusToStr(p.status));
end;
{ AverageSyncRate の実装 — アクティブなパイロットのシンクロ率平均を返します }
function AverageSyncRate(const pilots : array of TPilot) : Real;
var
total : Real;
count : Integer;
i : Integer;
begin
total := 0.0;
count := 0;
{ Low/High でオープン配列の添え字範囲を取得します }
for i := Low(pilots) to High(pilots) do begin
if pilots[i].status = statusActive then begin
total := total + pilots[i].sync_rate;
Inc(count);
end;
end;
if count > 0 then begin
AverageSyncRate := total / count;
end else begin
AverageSyncRate := 0.0;
end;
end;
{ -----------------------------------------------
INITIALIZATION セクション
— プログラム起動時に一度だけ実行されます
----------------------------------------------- }
initialization
WriteLn('[eva_pilots unit] UNIT が初期化されました。');
{ -----------------------------------------------
FINALIZATION セクション
— プログラム終了時に一度だけ実行されます
----------------------------------------------- }
finalization
WriteLn('[eva_pilots unit] UNIT が終了処理を実行しました。');
end.
eva_main.pas(メインプログラム)
{ eva_main.pas — eva_pilots UNIT を uses して利用するメインプログラムです }
{
コンパイルと実行:
fpc eva_main.pas && ./eva_main
(eva_pilots.pas が同じディレクトリにある必要があります)
}
program eva_main;
{ -----------------------------------------------
eva_pilots UNIT を使用宣言します
— INTERFACE で公開された型・定数・手続き・関数が使えます
----------------------------------------------- }
uses
eva_pilots;
var
pilots : array[1..PILOT_COUNT] of TPilot;
i : Integer;
avg : Real;
begin
{ -----------------------------------------------
パイロットデータを設定します
----------------------------------------------- }
{ 碇シンジ(Shinji Ikari)— 初号機パイロット }
pilots[1].name := 'Shinji Ikari';
pilots[1].unit_number := 1;
pilots[1].sync_rate := 400.0; { S2 機関覚醒時の推定値 }
pilots[1].status := statusMissing;
{ 綾波レイ(Rei Ayanami)— 零号機パイロット }
pilots[2].name := 'Rei Ayanami';
pilots[2].unit_number := 0;
pilots[2].sync_rate := 61.2;
pilots[2].status := statusActive;
{ 惣流・アスカ・ラングレー(Asuka Langley Soryu)— 弐号機パイロット }
pilots[3].name := 'Asuka Langley Soryu';
pilots[3].unit_number := 2;
pilots[3].sync_rate := 102.0;
pilots[3].status := statusInjured;
{ 鈴原トウジ(Toji Suzuhara)— 参号機(代理)パイロット }
pilots[4].name := 'Toji Suzuhara';
pilots[4].unit_number := 3;
pilots[4].sync_rate := 23.5;
pilots[4].status := statusInjured;
{ 渚カヲル(Kaworu Nagisa)— 第 17 使徒 / Eva パイロット }
pilots[5].name := 'Kaworu Nagisa';
pilots[5].unit_number := 2; { 弐号機への搭乗 }
pilots[5].sync_rate := 99.9;
pilots[5].status := statusMissing;
{ -----------------------------------------------
パイロット情報を一覧表示します
— PrintPilot は eva_pilots UNIT で定義されています
----------------------------------------------- }
WriteLn('========================================');
WriteLn(' NERV Evangelion Pilots Report');
WriteLn('========================================');
for i := 1 to PILOT_COUNT do begin
PrintPilot(pilots[i]);
WriteLn('');
end;
{ -----------------------------------------------
アクティブなパイロットのシンクロ率平均を求めます
— AverageSyncRate は eva_pilots UNIT で定義されています
----------------------------------------------- }
avg := AverageSyncRate(pilots);
WriteLn('Active Pilots Average Sync Rate : ', avg:0:1, '%');
WriteLn('========================================');
end.
fpc eva_main.pas && ./eva_main
Free Pascal Compiler version ...
Compiling eva_pilots.pas
Compiling eva_main.pas
Linking ./eva_main
[eva_pilots unit] UNIT が初期化されました。
========================================
NERV Evangelion Pilots Report
========================================
Unit-1 Shinji Ikari
Sync Rate : 400.0%
Status : Missing
Unit-0 Rei Ayanami
Sync Rate : 61.2%
Status : Active
Unit-2 Asuka Langley Soryu
Sync Rate : 102.0%
Status : Injured
Unit-3 Toji Suzuhara
Sync Rate : 23.5%
Status : Injured
Unit-2 Kaworu Nagisa
Sync Rate : 99.9%
Status : Missing
Active Pilots Average Sync Rate : 61.2%
========================================
[eva_pilots unit] UNIT が終了処理を実行しました。
finalization セクションの出力は FPC のバージョンによって表示されない場合があります。FPC 3.2.2 では表示されないことが確認されています。
よくあるミス
IMPLEMENTATION セクションで INTERFACE の宣言を重複して書く
IMPLEMENTATION セクションでは、手続き・関数の実装本体だけを書きます。INTERFACE に書いたヘッダ宣言(引数リストや戻り値型)を IMPLEMENTATION でも完全に重複させる必要はなく、手続き名のみで定義できます。Free Pascal では引数リストを省略した短縮形が認められています。
unit_impl_note.pas
unit unit_impl_note;
interface
procedure Greet(const name: string);
implementation
{ 省略形: 引数リストを省略できます(Free Pascal 拡張) }
procedure Greet;
begin
{ name はスコープ内で参照できます }
end;
end.
UNIT ファイル名と unit 宣言名を一致させない
Free Pascal では、ファイル名(拡張子なし)と unit 宣言に書いた名前は一致させる必要があります。一致しない場合はコンパイルエラーになります。
mymodule.pas(NG: ファイル名が mymodule なのに unit 宣言が別名)
unit OtherName; { NG: ファイル名 mymodule と一致しない }
interface
implementation
end.
Fatal: Unit name "OtherName" does not match filename "mymodule"
ファイル名と unit 宣言を一致させます。
mymodule.pas(OK)
unit mymodule; { ファイル名と一致させます }
interface
implementation
end.
概要
『Pascal』の UNIT はプログラムをファイル単位で分割するモジュール機構です。INTERFACE セクションに外部公開するシンボルを宣言し、IMPLEMENTATION セクションに実装を隠蔽することで、カプセル化と再利用性を実現できます。INITIALIZATION と FINALIZATION を使えばリソースの初期化・後片付けをモジュール内で自己完結させることができます。UNIT 内で定義した型をレコード型として使う詳しい使い方は RECORD(レコード型の基本) を、手続き・関数の定義の基礎は PROCEDURE(手続きの定義) および FUNCTION(関数の定義) を合わせて確認してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。