コンテンツにスキップ

Perl/class

出典: フリー教科書『ウィキブックス(Wikibooks)』


プログラミング > Perl > クラス


クラス

[編集]

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から導入された実験的な機能であり、将来のバージョンで変更される可能性があります。最新のリリースノートや公式ドキュメントを確認することをおすすめします。

class構文で実装予定でv5.38では未実装な機能
class構文はまだ実験的であり、非常に不完全です。以下のリストは、追加や変更が必要な作業の一部の概要を示しています。
ロール
ロールを宣言するためのいくつかの構文(おそらく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 構文では、フィールドやクラスに属性を付けることができます。属性は fieldclass 宣言の後にコロンで指定されます。例えば、: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 構文を使用すると、オブジェクト指向プログラミングをより直感的に行うことができます。しかし、まだ実験的な機能であるため、将来の変更に備えて柔軟性を持たせることが重要です。

脚註

[編集]
このページ「Perl/class」は、まだ書きかけです。加筆・訂正など、協力いただける皆様の編集を心からお待ちしております。また、ご意見などがありましたら、お気軽にトークページへどうぞ。