27

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";

私が抱えていた質問/混乱をコメントとしてコードに挿入しました。

4

7 に答える 7

53

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

例えば、

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

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

これにより、と、および対応する値の2 つのキーを持つハッシュを持つ%stuffサブルーチンが生成されます。foobeervodka

さて、OO Perl には、いくつかの追加の問題があります。矢印 ( ->) 演算子を使用してメソッドを呼び出すと、矢印の左側にあったものが@_配列の先頭にくっつきます。

だからあなたが言うならFoo->new( 1, 2, 3 );

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

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

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

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

于 2009-11-09T19:14:35.907 に答える
18

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

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

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

.2. 何が何をしているのかmy $type = shift;まったくわかりませんが、いつも見ています。必要ですか?

shiftwith no arguments は、 の頭から引数を取り、@_それを に代入し$typeます。オペレーターは->呼び出し元 (左側) を最初の引数としてサブルーチンに渡します。したがって、この行は引数リストからクラス名を取得します。そして、はい、あなたはそれを必要とします。

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

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

.4. 「my $self = {};」は何をしますか?

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

.5. どこ$self->{'High'} = $params{'High'};から$params{'High'}来たのですか?

このコードは、 に渡される引数に依存していますnewnewが のように呼び出された場合Foo->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;
}
于 2009-11-09T20:42:45.540 に答える
9

あなたの質問は 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 = ['高',42,'低',11];
于 2009-11-09T19:07:13.300 に答える
8

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

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

それを %hash に割り当てると、

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

これは、perl リスト/ハッシュ構築構文での別の言い方であり、同じこと","を意味します。"=>"

于 2009-11-09T19:10:51.670 に答える
5

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

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

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

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

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

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

于 2009-11-09T19:07:36.373 に答える
1

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

これらの回答はすべて優れていますが、 Mooseについて言及したいと思います。Moose はコンストラクターを簡単package Foo;use Moose;にします (コンストラクターが自動的に呼び出されますnew("new" という名前は必要に応じてオーバーライドできます) )

Moose のドキュメントに目を通した後 (これは全体的に非常に優れており、適切にググればチュートリアルのスニペットがさらにたくさんあります)、決して振り返ることはありませんでした。

于 2011-09-21T00:03:03.497 に答える