[ トップ | 一覧 | 更新履歴 ]

PerlCoding

PerlCGI

Perl5っぽくコードを書くには〜class化のヒント。

classとはpackageのことらしい。 subroutineもmethodも一緒だろう。

ファイル名をClassA.pmとして、少なくとも package ClassA;と宣言すればそれ以降のソースはClassAのclassのものとなります。

階層化ClassA::ClassSubなどの話はとりあえず後まわし。また、package宣言は宣言するたびにそれ以降の切り替えとなりますが、これも今は考えないこととします。 1ファイル(ClassA.pm)には1パッケージ宣言として説明します。

class method, instance method

class methodは、クラスの名前で呼び出されるmethodです。 クラスのインスタンスを生成したり、クラスのオブジェクトに直接影響を及ぼさない ようなとき(こっちは正しいかなぁ)にこの形式で呼び出されます。

コンストラクタ関数new()は典型的なクラスメソッドです。

    use ClassName;
    my  $obj = ClassName->new($para1,$para2);
    my  $dat = new ClassName($para1,$para2);

instance methodは、クラスのインスタンスから呼び出されるmethodです。

   $obj->func($para1,$para2,$para3;

最近は見かけなくなりましたが、

   ClassName::func1();
   ClassName::func2();
   ClassName::func3();

なんて感じで延々と関数を呼び出すような作りのパッケージがよくありました。 これは、subroutine(function,method)にpackegeの名前のついた呼出ができる関数、 サブルーチン群であり、クラスとは関係ない作りである、といえます。

methodとはclassのfunctionです。と言いきるとちと怖いのですが、class、objectという 概念を持ち出した処理系がclassと密接したfunctionをmethodと命名したのではないかと 思ってます。

#SmallTalkの頃だったかなぁ。messageって呼んでたっけ。

sub new()

コンストラクタとは言わないですね。と思ってたら言うそうです。 perl使う慣習でnewというサブルーチンでclassのデータ(インスタンス)を作ります。 他の言語だと'new'は予約語になっていますが、perlでは単にsubroutineの名前です。

一般に、hashの参照にblessでpackageの名前をつけることでそのデータを作ります。 典型的なnew()は、

Ex.1

    package ClassA;
    ...
    sub new
    {
         my  $class  = shift;
         my  %para   = @_;
         my  $self   = {%para};
         bless $self, $class;
    }

呼び出し側は、

    $obj = ClassA->new();
    $obj = ClassA->new;
    $obj = new ClassA();
    $obj = new ClassA;
    $obj = ClassA::new(ClassA);   # 普通は書かない
    $obj = ClassA::new ClassA;    # 普通は書かない

呼び出す方法は何種類かありますが、最後の2つは普通は書かないですね。 つーか書く意味ないし、分かりづらいし。

ClassA->func:あるいはfunc ClassA;は、package ClassAのsub funcが第1引数'ClassA'で呼び出されます。 なので$classには'ClassA'が入ります。 引数がなければ%paraは空のhashとなり、$selfには、%paraの内容がリスト化されたものが再度{}でhashとなり(やはり空のhash)、その参照が$selfに入ります。 $[str]はスカラー変数の表記ですが、スカラー変数には数値、文字列、参照を代入することができます。

bless祝福、洗礼を受けるとか、宗教的意味合いが強いようですが、変数がclassの名前を持つことになります。 ここでは$selfがClassAの名前を持つことになります。perl内部で関連付けられると考えたほうがよいか。宗教名をもらうということなのか? bless $self;だけなら、デフォルトでpackageの名前が入ります。 なんでわざわざ同じ名前が入ってるに決まってる$classを指定してるのか、 デフォルトでいいんじゃないか、という疑問が発生しますが、このことについては「継承」のところで説明します。

最後にこのsub newの戻り値はblessの結果が返ります。 つまり、$selfが返ります。 $selfの値はローカル変数への参照ですが、関数からreturnした後も、参照があるならその領域は内容が維持されます。 例えスコープから外れたとしてもです。 他の言語と異なるところです。 1つも参照がなくなったとき以降に解放されます。

Ex.1はソースコードのテンプレートと考えてもらって結構です。テンプレートでなかったら、

my $self={%para};

は my $self=\%para;の方が素直です。リストのコピーを作らないですから。 メンバ変数やら、プロパティやらはこの$self指すhashに設定することで実現します。 methodメソッド、function関数、subroutineサブルーチンなどはsubで定義します。 次は、Ex.1に手を入れて、

メンバ変数

同じ意味ですが、

これらをclass objectとみなします。

そのhashのkeyで名前付けられた値がメンバ変数となります。 そしてclassの識別名で呼び出されるmethodが決まります。

倍数をクラスメンバに登録しておいて、計算時にその倍数にかける値を渡し計算する クラス。 そんな、単純なクラスを作ってみます

    package Baisuu;
    #
    sub new
    {
       my  $class = shift;
       my  %baisuu = shift;
       my  $self = {
            baisuu => $baisuu,  # 最後の','は付けてもsyntaxは許される 
                                # なぜ許すかはそのうち書きます
       };
       bress $self,$class;
       $self;                # いちばん最後の評価が戻り値となるので
                             # bress $selfは$selfを返すため、$self;は省略できる
                             # return $self; がいちばん冗長な書き方
    }
    sub keisan
    {
        my $self = shift;
        my $val = shift;
        return $val * $self->{baisuu};  # 上と同じ理由でreturnは省略できる
    }

使うときは、

    use Baisuu;
    my  $obj = Baisuu->new(4);
    print $obj->keisan(3), "\n";
    print $obj->keisan(5), "\n";

とかね。

さあて、new()の説明のところとこのコーディングは違ってますよね。 そうです。この単純なクラスでも、また違った書き方があるのです。

new()の説明のポリシーを貫くのであれば、次のような書き方になります。

blessできる変数

変数なら、配列でもスカラ変数1個でもいいです。

   sub new 
   { 
       my $rv; 
       $v = 12; 
       $rv = \$v; 
       bless $rv; 
   } 

とか、

   sub new 
   { 
       my $ra; 
       $ra = ['init','run']; 
       bless $ra; 
   } 

なんてね。しかしながら、名前がkeyになるハッシュって言うのはとても便利なんで、 ハッシュでいきましょう。結局はハッシュ、配列などの参照を使ってデータ構造をあらわす ことになるので、ハッシュがクラスのメンバ変数になるというよりは、そのデータ構造の 大もとがハッシュにであるということです。

    sub new 
    { 
        my $rh; 
        $rh = { 
            namae      => undef, 
            todoufuken => undef, 
            jyusyo     => undef, 
            denwa      => undef, 
        }; 
        bless $rh; 
    } 

subroutineにハッシュ形式で引数を渡す

   package Baisuu; 
   ... 
   sub new 
   { 
      my  $class = shift; 
      my  %para  = @_; 
      my  $self = {%para}; 
      bress $self,$class; 
      $self; 
   } 
   sub keisan 
   { 
       my $self = shift; 
       my $val = shift; 
       $val * $self->{baisuu}; 
   } 
   ... 
   my $obj = Baisuu->new(baisuu=>4); 
   print $obj->keisan(3), "\n"; 
   print $obj->keisan(5), "\n"; 

このやりかただと、new関数に渡す引数はハッシュ形式で渡すことになります。

   func( 
       aaa => 'value1', 
       bbb => 127, 
       ccc => [123,456], 
       ddd => {val1=>'hello',val2=>'perl'} 
   ); 

たとえば上のように呼び出します。この呼び出し方だと、「引数に名前がついてる」ので 引数のkey=>valueの登場する順番が拘束されません。

   func( 
       bbb => 127, 
       ccc => [123,456], 
       ddd => {val1=>'hello',val2=>'perl'}, 
       aaa => 'value1' 
   ); 

でも同じ結果が期待されます。そう、プロトタイプなんて意味ないです。perlは型の自由度 が大きいので関数(subroutine)の引数の型、順番、個数をあらかじめ宣言するプロトタイプ なんてあまり意味がないと個人的には思ってます。それよりも引数に名前が付けられる こちらのやり方のほうがずっといい。

ああー。そういった意味でも、くれぐれもkeyにはaaaやらbbbやらの名前は付けない でください。その内容に相当する意味のある名前を付けてください。

特に引数のバリエーションが多く、省略が可能だったりするとこのやり方は有利です。 クラスが大きくなってきたときなどが当てはまります。 引数が数個で、subroutineの性質から拡張性が必要ないようなときは、引数に順番に 並べるsubroutineでもよいでしょう。どちらを選ぶかは結局はそのクラスの性質と subroutineの位置付けからプログラマが判断します。sampleのコードですむものなら もう、好きにやれば、といったところですが、汎用的な大きなライブラリとなるクラス だと、この辺をしっかりデザインしなければなりません。

また、今回のsampleでは、クラスの中で使わないkeyまでもメンバとして登録されてしまいます。

   Baisuu->new(baisuu=>14,yokeina_key=>15,iminonai_key=>16); 

いらないデータは登録しなければいいのでプログラマ同士、プロジェクト内でポリシーを 決めておいたほうがいいでしょう。 プライベートのメンバは_アンダーバーで始まるkeyにして、外からの定義が直接bless されるハッシュに登録されないようにする、などの仕組みが必要です。perl5には隠蔽機能 がないため、読めるから、変更できるからそうする、なんてことができてしまいます。 多くの場合徒労になるので、ポリシーを開発者全員に浸透させる方が重要と考えます。

厳密に作るなら、必要なkey以外、登録できないようにするのがいいのでしょうが、煩雑 になるし、それで受けられる恩恵はさほど大きくないと私は考えます。perlらしくない 気がしますね。それと、sampleのやり方だと継承するときにnewをoverrideしなくてすむ場合が多くなります。

これは継承のところで説明したいと思います。

ハッシュ形式のsubroutineの呼び出し側と定義側での引数受け渡し

  func(bbb,127,[123,456],{val1=>'hallo',val2=>'perl'}); 

=>,と同じに解釈されるので上のようにfuncに引数のリストが渡されます。 =>はkey,valueの対を明確にするために使われます。

func側では引数のリストはすべて@_に入ってきます。先頭がblessされたクラスオブジェクト(new()の$self)がわたってきます。

   %para = @_; 

ここで、リストからハッシュに変換されてます。この例だと、

   Baisuu->new(baisuu=>12,baisuu=>13); 

なんてときは、後が優先されbaisuuには13が設定されます。

delete と undef

deleteとundefはそれぞれ変数の状態です。deleteはハッシュにのみ使えます。 その状態を調べるには、それぞれexists,definedを使います。


GzuGzu (WikiWikiWeb clone) ver 1.00 pre2
このページはGzuGzuで作成されました.
yaino.com