Perl/class
クラス
[編集]Perl5.36までは、bless
を使ったパッケージベースのオブジェクト指向が採用されていました。
Perl5.38からは、新たにキーワードclass
が導入され、より一般的なクラスベースのオブジェクト指向言語のスタイルでコードを書けるようになりました。
また、class
構文はbless
の糖衣構文ではなく、新たなオブジェクト機構を提供しています。
classの宣言と利用
[編集]use v5.38; use feature 'class'; no warnings 'experimental::class'; class Hello { field $name :param; method say_hello { say "Hello, $name!"; } } my $hello = Hello->new(name => "Universe"); $hello->say_hello;
- 実行結果
Hello, Universe!
- このコードは、Perl 5.38を使用してクラスを使った"Hello, World!"の例です。
- まず、
use v5.38;
はPerlのバージョンを5.38に指定しています。次に、use feature 'class';
は、Perl 5.0から実験的に導入されたクラス機能を有効にしています。さらに、no warnings 'experimental::class';
は、クラス機能に関する実験的な警告を無効にしています。 class Hello { ... }
のブロックで、Hello
という名前のクラスを定義しています。field $name :param;
は、クラスのフィールドである$name
を定義しています。:param
は、$name
がコンストラクタの引数であることを示しています。method say_hello { ... }
のブロックで、say_hello
というメソッドを定義しています。say "Hello, $name!";
は、"Hello, $name!"というメッセージを表示しています。$name
はフィールドの値を参照しています。my $hello = Hello->new(name => "Universe");
では、Hello
クラスのインスタンスを作成しています。コンストラクタには、name
というキーワード引数とその値が渡されています。- 最後の行の
$hello->say_hello;
では、$hello
インスタンスのsay_hello
メソッドを呼び出しています。この結果、"Hello, Universe!"という出力が得られます。
- packeageとblessを使った等価な実装例
use v5.30; use feature 'signatures'; no warnings "experimental::signatures"; package Hello { sub new: prototype($$)($class, $name) { bless { name => $name, }, $class; } sub say_hello($self) { say "Hello, @{[ $self->{name} ]}!" } } my $hello = Hello->new("Universe"); $hello->say_hello;
- 実行結果
Hello, Universe!
- このコードは、Perl 5.30を使用してオブジェクト指向を使った"Hello, World!"の例です。
- 最初に、
use v5.30;
を使用してPerlのバージョンを5.30に指定しています。次に、use feature 'signatures';
は、サブルーチンに引数の型指定を行うための機能を有効にしています。さらに、no warnings "experimental::signatures";
は、引数の型指定に関する実験的な警告を無効にしています。 package Hello { ... }
のブロックで、Hello
という名前のパッケージ(クラス)を定義しています。sub new: prototype($$)($class, $name) { ... }
は、new
というサブルーチン(コンストラクタ)を定義しています。prototype($$)
は、引数の型指定を行っています。$class
と$name
はそれぞれクラス名と名前の引数を表しています。bless
関数を使用して、name
フィールドを持つハッシュリファレンスを作成し、それをクラスに対してブレス(関連付け)しています。sub say_hello($self) { ... }
は、say_hello
というサブルーチン(メソッド)を定義しています。$self
は、メソッドが呼び出されるインスタンス自体を表します。$self->{name}
を参照して、"Hello, $self->{name}!"というメッセージを表示しています。my $hello = Hello->new("Universe");
では、Hello
クラスのインスタンスを作成しています。引数として"Universe"が渡されます。- 最後の行の
$hello->say_hello;
では、$hello
インスタンスのsay_hello
メソッドを呼び出しています。この結果、"Hello, Universe!"という出力が得られます。
- 小まとめ
- パッケージ宣言とは異なり、クラス宣言では
class
というキーワードを使用します。 - クラス宣言はブロック構文または文構文のいずれかで行うことができます。
- クラス宣言内で、
field
というキーワードを使用してフィールド(クラスのインスタンス変数)を宣言できます。フィールドはクラスのスコープ内でのみ参照可能であり、各インスタンスごとに独自のフィールドの値を持ちます。 - クラス宣言内で、
method
というキーワードを使用してメソッド(クラスのサブルーチン)を宣言できます。メソッドはクラスのインスタンス内で呼び出されることを意図しており、自動的に特殊変数$self
が生成され、メソッド内で使用されます。 - クラスやフィールドには属性を指定することができます。例えば、クラスの継承を指定する
:isa
属性や、フィールドの初期化を制御する:param
属性があります。
- これらの機能を使用することで、Perlにおいてよりオブジェクト指向プログラミングのパラダイムに則ったコーディングが行えるようになります。
- ただし、この機能は実験的なものであり、将来のバージョンで変更されたり、削除されたりする可能性があります。最新のリリースノートや公式ドキュメントを参照することをおすすめします。
特殊コードブロック
[編集]ADJUST
[編集]ADJUSTブロックは、Perlのクラス構文で使用される特殊なブロックです。このブロックはクラスの宣言内で定義され、オブジェクトの構築中に実行されるカスタムコードを含めるために使用されます。 ADJUSTブロックは、クラスのフィールド(インスタンス変数)やメソッドが初期化される前に実行されます。つまり、オブジェクトが構築される過程でフィールドの値を調整するために使用されます。
以下にADJUSTブロックの基本的な構文を示します:
class MyClass { field $field1; field $field2; ADJUST { # フィールドの値を調整するカスタムコード } method my_method { # メソッドの実装 } }
ADJUSTブロックは、クラス内でフィールドの初期値を設定したり、関連するフィールドの相互作用を制御したりするために使用されます。例えば、複数のフィールドの初期値に基づいて他のフィールドを計算する場合に便利です。 ADJUSTブロック内では、特殊変数「$self」を介して現在のオブジェクトインスタンスにアクセスすることができます。また、ADJUSTブロック内で定義された変数は、そのブロック内でのみ有効です。 ADJUSTブロックは、クラスの宣言内で複数回定義することができます。その場合、定義された順序に従って順番に実行されます。 なお、ADJUSTブロックはPerl 5.38.0から導入された実験的な機能であり、将来のバージョンで変更される可能性があります。最新のリリースノートや公式ドキュメントを確認することをおすすめします。
- ロール
- ロールを宣言するためのいくつかの構文(おそらくroleキーワード)と、クラスにロールを組み込むための構文(おそらく:does()属性)。
- ADJUSTブロックへのパラメータ
- ADJUSTブロックが名前付きパラメータを受け取ることができることを宣言するための構文。これらのパラメータはクラスのコンストラクタのAPIの一部になります。これは、サブルーチンのシグネチャに名前付き引数を追加するという似たような計画に触発されたものかもしれません。
class X { ADJUST (:$alpha, :$beta = 123) { ... } } my $obj = X->new(alpha => 456);
- ADJUSTブロックの真のブロック化
- 現在、各ADJUSTブロックは独自のCVでラップされ、フルのENTERSUBオーバーヘッドを伴って呼び出されます。すべてのフィールド初期化式が同じCV内に表示される仕組みを使って、ADJUSTブロックも同様に真のブロックとして使用できるようにすることができます。これにより、クラスに複数のADJUSTブロックがある場合に、呼び出しを高速化することができます。
- アクセッサ生成属性
- フィールドに対してアクセッサメソッドの生成を要求する属性。おそらく:readerと:writerです。
class X { field $name :reader; }
- 次のものと同等です。
class X { field $name; method name { return $name; } }
- メタプログラミング
- メタプログラミングAPIの拡張(現在RFC0022で提案されている)で、クラス、メソッド、フィールド、ADJUSTブロックなどのクラスに関連する詳細を追加します。
- 拡張のカスタマイズ
- 外部のモジュールがクラスシステムとやり取りする方法を提供する方法。これには、新しいクラスやフィールド属性を提供する能力が含まれます。
プラグマ
[編集]use feature 'class';
warnings
[編集]no warnings 'experimental::class';
class/field/method
[編集]Perlの class
構文は、オブジェクト指向プログラミングを行うための新しい機能であり、Perl 5.32から導入されました。この構文は、他の言語で一般的に見られるクラス定義のスタイルに近づけることを目指しています。以下に、Perlの class
構文の基本的な解説を行います。
class
キーワード
[編集]class
キーワードは、新しいクラスを宣言するために使用されます。クラス内で使用されるメソッドやフィールドを定義するためのブロックが続きます。例えば:
class MyClass { # クラスの定義 }
フィールドの宣言(field
キーワード)
[編集]field
キーワードは、クラス内のフィールドを宣言します。フィールドはクラスのインスタンスごとに独自の値を持ちます。例えば:
class MyClass { field $name; field $age; }
メソッドの宣言(method
キーワード)
[編集]method
キーワードは、クラス内のメソッドを定義します。これらのメソッドは、クラスのインスタンスに関連付けられています。例えば:
class MyClass { method greet { say "Hello, World!"; } }
コンストラクタ(new
メソッド)
[編集]new
メソッドは、クラスのインスタンスを生成するための特別なメソッドです。class
ブロック内に new
メソッドを定義する必要はありません。new
メソッドは自動的に提供されます。例えば:
my $obj = MyClass->new;
クラスの継承
[編集]Perlの class
構文では、継承もサポートされています。class
宣言の後に :isa()
属性を付けることで、他のクラスを継承することができます。例えば:
class SubClass :isa(BaseClass) { # サブクラスの定義 }
ADJUST
ブロック
[編集]ADJUST
ブロックは、クラスのインスタンスが構築された直後に実行されるブロックです。これは、インスタンスを調整するためのカスタムコードを提供するために使用されます。たとえば、フィールドの初期化やインスタンスの設定を行うのに便利です。
class MyClass { field $name; field $age; ADJUST { $name = "John"; $age = 30; } }
ADJUST
ブロック内では、クラスのフィールドに直接アクセスできます。このブロックは、インスタンスのコンストラクション中に実行され、各インスタンスごとに一度だけ実行されます。
クラスの利用
[編集]class
構文を使用して定義されたクラスは、通常のPerlのモジュールと同様に使用されます。use
文を使ってクラスをインポートし、そのクラスのインスタンスを作成します。
use MyClass; my $obj = MyClass->new;
new
メソッドは自動的に提供されるため、class
ブロック内に new
メソッドを定義する必要はありません。
属性(Attributes)
[編集]Perlの class
構文では、フィールドやクラスに属性を付けることができます。属性は field
や class
宣言の後にコロンで指定されます。例えば、:param
属性はフィールドをコンストラクタのパラメータとして使用することを示します。
フィールドの属性
[編集]フィールドには、:param
属性を含むさまざまな属性を指定することができます。これらの属性は、フィールドの動作をカスタマイズします。たとえば、:param
属性は、フィールドをコンストラクタのパラメータとして使用することを示します。
class MyClass { field $name :param; field $age :param; }
:param
属性を使用すると、コンストラクタを呼び出す際にフィールドの値を指定できます。
my $obj = MyClass->new(name => "John", age => 30);
このように、フィールドの属性を使用することで、コンストラクタの引数の扱いを柔軟に制御できます。
メソッドの属性
[編集]メソッドにも属性を指定することができますが、現在のところ実装されていません。
未来の展望
[編集]Perlの class
構文はまだ実験的な段階にあり、今後のバージョンでさらなる機能や改善が期待されています。例えば、ロール(Role)のサポートやメタプログラミングの拡張などが考えられます。
このように、Perlの class
構文を使用すると、オブジェクト指向プログラミングをより直感的に行うことができます。しかし、まだ実験的な機能であるため、将来の変更に備えて柔軟性を持たせることが重要です。