2011-01-26 8 views
2

でメソッド名として変数を使用:基本的に私はそうのようなperlのスクリプト(簡易)を持っているPerlの

my $dh = Stats::Datahandler->new(); ### homebrew module 

my %url_map = (
    '/(article|blog)/' => \$dh->articleDataHandler, 
    '/video/' => \$dh->nullDataHandler, 
); 

、私は%url_mapをループするつもりだ、と現在のURLがキーと一致した場合そのキーの値によって指さ私は関数を呼び出したい:

foreach my $key (keys %url_map) { 
    if ($url =~ m{$key}) { 
     $url_map{$key}($url, $visits, $idsite); 
     $mapped = 1; 
     last; 
    } 
} 

しかし、私はメッセージを取得しています:

Can't use string ("/article/") as a subroutine ref while "strict refs" in use at ./test.pl line 236.

行236は、行$url_map{$key}($url, $visits, $idsite);になります。

私はこれまで同様のことをしてきましたが、私は通常、モジュールを使わずに関数にパラメータを渡しています。

+0

の可能複製(http://stackoverflow.com/questions/4229562/how-:あなたはこれを必要とする場合、私は上記にリンクされている質問を参照してください。 to-take-code-constructor) –

+2

あなたの問題はメソッドを呼び出すことではなく、そのメソッドへの参照を格納することです。上記のdupリンクを参照してください。 –

+1

も参照してください[Perlでハッシュに格納されている関数名を呼び出す方法は?](http://stackoverflow.com/questions/1836178/how-do-i-他の半分(参照をあなたがそれを格納した後に呼び出す)のために、その部分も間違っているため、perlでハッシュインされた関数名を呼び出す)。 – Ether

答えて

3

これはDUPであるにもかかわらず、ここで回答されているので、私も正しい答えを投稿することがあります。

あなたがする必要がどのような値として、コードの参照が格納されますあなたのハッシュで。メソッドへのコード参照を取得するには、すべてのオブジェクトのUNIVERSAL::canメソッドを使用できます。しかし、メソッドがinvocantを渡す必要があるので、これでは不十分です。この手法は、引数で呼び出されると、今度はそれらの引数を持つ適切なメソッドを呼び出しますことをハッシュにコードの参照を格納します

my %url_map = (
    '/(article|blog)/' => sub {$dh->articleDataHandler(@_)}, 
    '/video/'   => sub {$dh->nullDataHandler(@_)}, 
); 

:だから、->canをスキップし、それをこのように書くことが最も明確です。

この回答は重要な考慮事項を省略し、callerが正しく動作することを確認しています。 [?コンストラクタにコードリファレンスを取る方法】

How to take code reference to constructor?

+0

「必要性」がこれに対して強すぎます。これを行う方法の1つですが、単純な方法よりも多くの作業と工学が必要です。 –

+0

@brian =>あなたが「必要性」のために投票した場合、それはかなり些細なことです...そうでなければ、ダウン投票者、説明してください? –

+0

私は「もっと多くの仕事と工学」のために下降しました。 –

0

これを処理する最善の方法は、匿名サブルーチンでメソッド呼び出しをラップすることです。このサブルーチンは後で呼び出すことができます。また、qr演算子を使用して、適切な正規表現を格納し、パターンを補間するのが厄介なことを避けることもできます。例えば、

my @url_map = ( 
    { regex => qr{/(article|blog)/}, 
     method => sub { $dh->articleDataHandler } 
    }, 
    { regex => qr{/video/}, 
     method => sub { $dh->nullDataHandler } 
    } 
); 

は、このようにそれを介して実行:

foreach my $map(@url_map) { 
    if ($url =~ $map->{regex}) { 
     $map->{method}->(); 
     $mapped = 1; 
     last; 
    } 
} 

このアプローチは、ハッシュの配列ではなくフラットハッシュを使用して、その結果が含まREF各正規表現は、匿名サブ関連付けることができ実行するコード->()の構文は、subrefを逆参照し、それを呼び出します。また、サブリファレンスにパラメータを渡すこともでき、サブブロック内の@_に表示されます。このメソッドを使用して、必要に応じてパラメータを使用してメソッドを呼び出すことができます。

3

あなたは問題を熟考しています。 2つのスラッシュの間の文字列を取り出し、ハッシュのメソッド名(参照ではない)を検索します。 Perlでは、スカラー変数をメソッド名として使用できます。値は、あなたが実際に呼び出すメソッド次のようになります。

%url_map = (
     'foo' => 'foo_method', 
    ); 

my($type) = $url =~ m|\A/(.*?)/|; 
my $method = $url_map{$type} or die '...'; 
$dh->$method(@args); 

反復のほとんどはあなたに役に立たない任意のループを取り除くようにしてください。 :)私はそれはあなたがない限り(あなたがcanで特定のオブジェクトのメソッドへの参照を取得することができ、問題

に近いだにもかかわらず、好きではありません


私の前の回答、それ以外の方法で自分自身を実装しました)。

my $dh = Stats::Datahandler->new(); ### homebrew module 

my %url_map = (
    '/(article|blog)/' => $dh->can('articleDataHandler'), 
    '/video/'   => $dh->can('nullDataHandler'), 
); 

方法を呼び出して結果を参照します。それはあなたが延期された行動のために望むものではありません。

これを取得したら、メソッド呼び出しではなく、通常のサブルーチン逆参照として呼び出します。それはすでに、その目的を知っている:

BEGIN { 
package Foo; 

sub new { bless {}, $_[0] } 
sub cat { print "cat is $_[0]!\n"; } 
sub dog { print "dog is $_[0]!\n"; } 
} 

my $foo = Foo->new; 

my %hash = (
    'cat' => $foo->can('cat'), 
    'dog' => $foo->can('dog'), 
    ); 

my @tries = qw(cat dog catbird dogberg dogberry); 

foreach my $try (@tries) { 
    print "Trying $try\n"; 
    foreach my $key (keys %hash) { 
    print "\tTrying $key\n"; 
     if ($try =~ m{$key}) { 
      $hash{$key}->($try); 
      last; 
      } 
     } 
    } 
+0

' - > can'を使って参照を取得するだけでは不十分です。invocantが必要です。リンクされたdupの質問を参照してください –

+0

'できます'はすべてのモジュールの組み込み能力ですか? –

+0

はUNIVERSALから来ることができます。これは、すべてのモジュールがcan()と同じ動作をしているわけではありません。しかし、頭痛は困難なことに付随しているので、その部分を忘れてしまいます。 –

関連する問題