高見知英の技術ログ

技術関係のログをQiitaから移行してきました。プログラミングのほか、使っているアプリの細かい仕様についてなど書いていきます。

Lazarus(というかPascal)のデータ型について

このブログはLazarus(FreePascal)アドベントカレンダー23日目の記事です。

qiita.com

今回の内容はPascalのデータ型について。

Pascalのデータ型はちょっと特徴的で(といっても、最近PythonJavaScriptなど明確に型のない言語しかつかってないのでどれだけ特殊なのかは分からないのですが)、いくつかの種類のデータ型があります。

  • クラス型
  • 構造体型
  • プリミティブ型
  • 配列型
  • ポインタ型
  • 関数型(関数のポインタ型)
  • メソッド型(メソッドのポインタ型)

特に注意が必要なデータ型いろいろ

プリミティブ型の扱い

プリミティブ型だけみても結構な種類があり、数値だけでもInteger、Cardinal型、DWord型、QWord型、UInt型などいろいろな型があります。

基本的にはOSのビット数などで定義が切り替わるInteger型かCardinal型あたりを使うのが安全 ということだったと思いますが(Delphiのときには)、型を指定してデータ型を要求してきたり、戻り値が指定されたりすることもあり、実質おなじデータ型でも型が違うと引数に指定できない場合があるので、そういうものだくらいは覚えておいた方がいいです。

LCLオブジェクトなどのCaptionプロパティの型であるTCaptionも、辿っていけばString型です。先日ちょっと触れたヘルパークラスメソッドも、使うことができます。

これらはLazarusのソースエディタ上でデータ型にカーソルを合わせるか、Ctrlキーを押しながらクリックすることで、大元となっているデータ型を知ることができます。正直この辺はぱっと見分かりづらいので気になったら調べておくと良さそう。

f:id:TakamiChie:20211215111713p:plain
データ型の情報表示

また、Windows APIやOLEオブジェクトにデータ型を引き渡すときはPCharやPWCharなどのデータ型を指定する必要があります。これはポインタ型ではありますが、文字列型をキャストすることで作成できます。

uses
  Windows…;


{中略}

procedure TForm1.FormCreate(Sender: TObject);
begin
  SetWindowText(Self.Handle, PChar('TEST'));
end;

クラス型

また、Pascalにはガベージコレクションがありませんので、クラス型の場合データの解放処理が必要となります(Object.Freeメソッド)。Pythonを使ってる身からすると「withでいいやん」くらいに思ってしまうのですが、そういう便利構文はないようです。

constructor TLocalizer.Create;
var
  r: TResourceStream;
begin
  FLanguage:='def';
  r := TResourceStream.Create(HINSTANCE, 'LANG', RT_RCDATA);
  try
    FLocalizeFile := TMemIniFile.Create(r, []);
  finally
    r.Free;
  end;
end;

なお、クラス型以外のデータはスコープから抜けた時点で解放されるのでメモリの解放処理は必要ありません。

配列型

Pascalでは関数が特定の型の配列を返すときなどは、配列型の定義が必要です。

type TIntArray= array of Integer;

function Test: TIntArray;
begin
  Result:=[1,2];
end;

begin
  WriteLn(Test[0]); // -> 1
  ReadLn;
end.

ただし、開発環境が結構よろしくガイドを表示してくれるので…。

しかしそこはさすが静的型付け言語。Lazarusが結構適切にデータ型の情報を表示してくれるので、それほどには迷わなかったりします。

PythonJavaScriptだとそうもいかないのでここは「さすがPascal…」と思ってしまいます(まあ他の言語でも静的型付け言語ならそんなもんだとは思いますが)。

とはいえ分かりづらい部分があるのに変わりはないので、マウスホバー時のヒントやCtrl+Spaceキーなどで表示されるインテリセンスなどを上手く活用したコーディングをしていきましょう。