web-dev-qa-db-ja.com

オブジェクト指向のPerlコンストラクター構文と名前付きパラメーター

Perlコンストラクターで何が起こっているのか少し混乱しています。私はこれらの2つの例を見つけました perldoc perlbot

package Foo;

#In Perl, the constructor is just a subroutine called new.
sub new {
  #I don't get what this line does at all, but I always see it. Do I need it?
  my $type = shift;

  #I'm turning the array of inputs into a hash, called parameters.
  my %params = @_;

  #I'm making a new hash called $self to store my instance variables?
  my $self = {};

  #I'm adding two values to the instance variables called "High" and "Low".
  #But I'm not sure how $params{'High'} has any meaning, since it was an
  #array, and I turned it into a hash.
  $self->{'High'} = $params{'High'};
  $self->{'Low'} = $params{'Low'};

  #Even though I read the page on [bless][2], I still don't get what it does.
  bless $self, $type;
}

そして別の例は次のとおりです。

package Bar;

sub new {
  my $type = shift;

  #I still don't see how I can just turn an array into a hash and expect things
  #to work out for me.
  my %params = @_;
  my $self = [];

  #Exactly where did params{'Left'} and params{'Right'} come from?
  $self->[0] = $params{'Left'};
  $self->[1] = $params{'Right'};

  #and again with the bless.
  bless $self, $type;
}

そして、これらのオブジェクトを使用するスクリプトは次のとおりです。

package main;

$a = Foo->new( 'High' => 42, 'Low' => 11 );
print "High=$a->{'High'}\n";
print "Low=$a->{'Low'}\n";

$b = Bar->new( 'Left' => 78, 'Right' => 40 );
print "Left=$b->[0]\n";
print "Right=$b->[1]\n";

私はコメントとしてコードに私が持っていた質問/混乱を注入しました。

27
Thomas Owens

質問の主な目的に答えるために、ハッシュは_key => value_ペアのリストとして初期化できるため、そのようなリストを関数に送信してから、_@__をハッシュに割り当てることができます。これは、Perlで名前付きパラメーターを実行する標準的な方法です。

例えば、

_sub foo { 
    my %stuff = @_;
    ...
}

foo( beer => 'good', vodka => 'great' );
_

これにより、サブルーチンfooの_%stuff_は、2つのキーbeervodka、および対応する値を持つハッシュを持ちます。

さて、OO Perlには、いくつかの追加のしわがあります。矢印(_->_)演算子を使用してメソッドを呼び出すと、矢印の左側にあるものがすべて貼り付けられます。 _@__配列の始まり。

したがって、Foo->new( 1, 2, 3 )と言うと;

次に、コンストラクター内で、_@__は次のようになります:_( 'Foo', 1, 2, 3 )_。

したがって、引数なしで暗黙的に_@__を操作するshiftを使用して、最初のアイテムを_@__から取得し、それを_$type_に割り当てます。その後、_@__には名前と値のペアだけが残り、便宜上ハッシュに直接割り当てることができます。

次に、その_$type_値をblessに使用します。 blessが行うのは、参照(最初の例ではハッシュ参照)を取得して、「この参照は特定のパッケージに関連付けられている」と言うことだけです。アラカザム、あなたは物を持っています。

_$type_には、パッケージの名前である文字列「Foo」が含まれていることに注意してください。 しないblessに2番目の引数を指定すると、現在のパッケージの名前が使用されます。これはこの例でも機能しますが、not =継承されたコンストラクターで動作します。

53
friedo

.1。 Perlでは、コンストラクターはnewと呼ばれる単なるサブルーチンです。

はい、慣例により、newはコンストラクターです。また、初期化を実行する場合と実行しない場合があります。 newは、成功するとオブジェクトを返すか、オブジェクトの作成を妨げるエラーが発生した場合は例外(die/croak)をスローする必要があります。

コンストラクターには好きな名前を付けたり、好きなだけコンストラクターを設定したり、blessオブジェクトを任意の名前空間に構築したりすることもできます(これは良い考えではありません)。

.2。 _my $type = shift;_の機能がまったくわかりませんが、常に表示されます。必要ですか?

引数のないshiftは、_@__の先頭から引数を取り、それを_$type_に割り当てます。 _->_演算子は、サブルーチンへの最初の引数として呼び出し側(左側)を渡します。したがって、この行は引数リストからクラス名を取得します。そして、はい、あなたはそれを必要とします。

.3。入力の配列はどのようにして_%params_ハッシュになりますか? _my %params = @_;_

ハッシュへの割り当てはリストコンテキストで行われ、リストアイテムのペアはキーと値のペアとしてグループ化されます。したがって、_%foo = 1, 2, 3, 4;_は、_$foo{1} == 2_および_$foo{3} == 4_のようなハッシュを作成します。これは通常、サブルーチンの名前付きパラメーターを作成するために行われます。サブに奇数の引数が渡された場合、警告が有効になっていると警告が生成されます。

.4。 'my $ self = {}; `は何をしますか?

この行は、匿名のハッシュ参照を作成し、それを字句スコープの変数_$self_に割り当てます。ハッシュ参照は、オブジェクトのデータを格納します。通常、ハッシュ内のキーには、オブジェクト属性への1対1のマッピングがあります。したがって、クラスFooに属性「size」と「color」がある場合、Fooオブジェクトの内容を調べると、_$foo = { size => 'm', color => 'black' };_のようなものが表示されます。

.5。 _$self->{'High'} = $params{'High'};_が与えられた場合、_$params{'High'}_はどこから来ますか?

このコードは、newに渡される引数に依存しています。 newFoo->new( High => 46 )のように呼び出された場合、質問3に従って作成されたハッシュは、キーHigh(46)の値を持ちます。この場合、_$self->{High} = 46_と言うのと同じです。ただし、メソッドがFoo->new()のように呼び出された場合、値は使用できず、_$self->{High} = undef_があります。

.6。 blessは何をしますか?

blessは参照を受け取り、特定のパッケージに関連付けるため、それを使用してメソッド呼び出しを行うことができます。 1つの引数を使用すると、参照は現在のパッケージに関連付けられます。 2つの引数を使用して、2番目の引数は参照を関連付けるパッケージを指定します。コンストラクターがサブクラスに継承され、引き続き適切に機能できるように、常に2つの引数形式を使用することをお勧めします。

最後に、古典的なOO Perlを使用して作成するのと同じように、ハッシュベースのオブジェクトアクセサーを書き直します。

_package Foo;

use strict;
use warnings;
use Carp qw(croak);

sub new {
    my $class = shift;

    croak "Illegal parameter list has odd number of values" 
        if @_ % 2;

    my %params = @_;

    my $self = {};
    bless $self, $class;

    # This could be abstracted out into a method call if you 
    # expect to need to override this check.
    for my $required (qw{ name rank serial_number  });
        croak "Required parameter '$required' not passed to '$class' constructor"
            unless exists $params{$required};  
    }

    # initialize all attributes by passing arguments to accessor methods.
    for my $attrib ( keys %params ) {

        croak "Invalid parameter '$attrib' passed to '$class' constructor"
            unless $self->can( $attrib );

        $self->$attrib( $params{$attrib} );
    }

    return $self;
}
_
18
daotoad

まだ取り扱われていないいくつかのポイント:

Perlでは、コンストラクターはnewと呼ばれる単なるサブルーチンです。

完全ではありません。コンストラクターをnewと呼ぶのは、単なる慣例です。あなたはそれを好きなように呼ぶことができます。 Perlの観点からは、その名前について特別なことは何もありません。

bless $self, $type;

どちらの例も、blessの結果を明示的に返していません。とにかく暗黙のうちにそうすることをあなたが知っていることを願っています。

9
innaM

あなたの質問はOO Perlについてではありません。あなたはデータ構造について混乱しています。

ハッシュは、リストまたは配列を使用して初期化できます。

my @x = ('High' => 42, 'Low' => 11);
my %h = @x;

use Data::Dumper;
print Dumper \%h;
 $ VAR1 = {
 '低' => 11、
 '高' => 42 
}; 

blessed参照でメソッドを呼び出すと、メソッドが受け取る引数リストの前に参照が追加されます。

#!/usr/bin/Perl

package My::Mod;

use strict;
use warnings;

use Data::Dumper;
$Data::Dumper::Indent = 0;

sub new { bless [] => shift }

sub frobnicate { Dumper(\@_) }

package main;

use strict;
use warnings;

my $x = My::Mod->new;

# invoke instance method
print $x->frobnicate('High' => 42, 'Low' => 11);

# invoke class method
print My::Mod->frobnicate('High' => 42, 'Low' => 11);

# call sub frobnicate in package My::Mod
print My::Mod::frobnicate('High' => 42, 'Low' => 11);

出力:

 $ VAR1 = [bless([]、 'My :: Mod')、 'High'、42、 'Low'、11]; 
 $ VAR1 = ['My :: Mod' 、 'High'、42、 'Low'、11]; 
 $ VAR1 = ['High'、42、 'Low'、11]; 
9
Sinan Ünür

配列をハッシュに割り当てると、Perlは配列内の交互の要素をキーと値として扱います。あなたの配列は次のように見えます

my @array = (key1, val1, key2, val2, key3, val3, ...);

それを%hashに割り当てると、次のようになります。

my %hash = @array;
# %hash = ( key1 => val1, key2 => val2, key3 => val3, ...);

これは、Perlリスト/ハッシュ構築構文で","および"=>"同じことを意味します。

8
Corey Porter

Perlでは、サブルーチンへのすべての引数は、事前定義された配列@_を介して渡されます。

shiftは、@_配列から最初の項目を削除して返します。 Perl OOでは、これはメソッド呼び出しです。通常、コンストラクターのクラス名と他のメソッドのオブジェクトです。

ハッシュはフラット化され、リストによって初期化できます。サブルーチンへの名前付き引数をエミュレートするのは一般的なトリックです。例えば.

Employee->new(name => 'Fred Flintstone', occupation => 'quarry worker');

(シフトオフされた)クラス名を無視すると、奇数要素がハッシュキーになり、偶数要素が対応する値になります。

my $self = {}は、インスタンスデータを保持するための新しいハッシュ参照を作成します。 bless関数は、通常のハッシュ参照$selfをオブジェクトに変換するものです。参照をクラスに属するものとして識別するメタデータを追加するだけです。

5
Michael Carman

はい、私はここで少しネクロマンサーになっていることを知っていますが...

これらの答えはすべて素晴らしいですが、私は言及したいと思いました ムース 。 Mooseはコンストラクターを簡単にします(package Foo;use Moose;は、newというコンストラクターを自動的に提供します(ただし、必要に応じて「new」という名前をオーバーライドできます))が、必要に応じて 構成可能性を奪うことはありません

Mooseのドキュメント(全体的にはかなり良いです。適切にグーグルすると、チュートリアルのスニペットがたくさんあります)を一度調べたら、振り返ることはありませんでした。

1
user554546