2009-10-27 56 views
10

是否可以在Perl中動態指定一個類並訪問該類中的靜態方法?這是不行的,但足以說明我想做什麼:我可以在Perl中訪問動態指定類中的靜態方法嗎?

use Test::Class1; 
    my $class = 'Test::Class1'; 
    $class::static_method();  

我知道我能做到這一點:

$class->static_method(); 

,並忽略傳遞給static_method類的名字,但我不知道是否有一個更好的方法。

+2

Upvoted幫我浪費了15分鐘我的僱主的時間。 :) – Ether 2009-10-27 23:22:02

+0

呃我的意思是花..當然富有成效! – Ether 2009-10-27 23:22:59

回答

4

我不知道這樣做的特別好的方式,但也有一些不太好的方面,比如這個程序:

#!/usr/bin/perl -w 

use strict; 

package Test::Class1; 

sub static_method { 
    print join(", ", @_) . "\n"; 
} 

package main; 

my $class = "Test::Class1"; 

{ 
    no strict "refs"; 
    &{${class}. "::static_method"}(1, 2, 3); 
} 

我已經包含了一個$class變量,因爲這是你怎麼問問題,並說明如何在運行時選擇課程名稱,但如果您事先知道該課程,則可以輕鬆地致電&{"Test::Class1::static_method"}(1, 2, 3);

請注意,如果您有開啓課程,則必須關閉strict "refs"

+0

@Tim我現在明白了。對不起,不必要的編輯。我發佈了一個使用字符串'eval'的解決方案來顯示使用代碼作爲模板的另一種方法。 – 2009-10-27 22:59:08

+1

@Sinan不是問題!讓我有機會進一步解釋並首次使用「回滾」功能。 :-) – Tim 2009-10-27 23:00:22

1

您可以使用字符串eval

#!/usr/bin/perl 

use strict; use warnings; 

package Test::Class1; 

sub static_method { 
    print join(", ", @_) . "\n"; 
} 

package main; 

my $class = 'Test::Class1'; 
my $static_method = 'static_method'; 

my $subref = eval q{ \&{ "${class}::${static_method}" } }; 
$subref->(1, 2, 3); 

輸出:

 
C:\Temp> z 
1, 2, 3 

基準:

#!/usr/bin/perl 

use strict; use warnings; 

package Test::Class1; 

sub static_method { "@_" } 

package main; 

use strict; use warnings; 
use Benchmark qw(cmpthese); 

my $class = 'Test::Class1'; 
my $static_method = 'static_method'; 

cmpthese -1, { 
    'can' => sub { my $r = $class->can($static_method); $r->(1, 2, 3) }, 
    'eval' => sub { 
     my $r = eval q/ \&{ "${class}::${static_method}" } /; 
     $r->(1, 2, 3); 
    }, 
    'nostrict' => sub { 
     no strict "refs"; 
     my $r = \&{ "${class}::static_method" }; 
     $r->(1, 2, 3); 
    } 
}; 

輸出:

 
      Rate  eval  can nostrict 
eval  12775/s  --  -94%  -95% 
can  206355/s 1515%  --  -15% 
nostrict 241889/s 1793%  17%  -- 
+1

現在我想知道'不嚴格'refs''和'eval'方法的優點/缺點。如果子程序未定義,兩者都報告相同的錯誤。從速度的角度來看,'沒有嚴格的'refs'方法似乎是明顯的贏家(只做了一個簡單的測試)。 – Inshallah 2009-10-27 23:15:28

+1

我也傾向於傾向於涉及'eval「」''的任何解決方案。 – Ether 2009-10-27 23:18:37

+0

我忘了'可以'。告訴你我很少做這樣的事情。 – 2009-10-27 23:22:58

10

是!嚴格執行的方法是使用can

package Foo::Bar; 
use strict; 
use warnings; 

sub baz 
{ 
    return "Passed in '@_' and ran baz!"; 
} 

package main; 
use strict; 
use warnings; 

my $class = 'Foo::Bar'; 

if (my $method = $class->can('baz')) 
{ 
    print "yup it can, and it "; 
    print $method->(); 
} 
else 
{ 
    print "No it can't!"; 
} 

can返回對方法undef/false的引用。然後您只需使用dereferene語法來調用該方法。

它提供:

 
    > perl foobar.pl 
    yup it can, and it Passed in '' and ran baz! 
+1

+1'can'是imo最不瘋狂的方式。它仍然會導致::不能做的整個繼承事件,但它會讓你繞過整個傳遞的$ self/$ classname作爲$ _ [0]行爲。 – 2009-10-27 23:27:08

+1

至少,如果它是一個模塊,很可能沒有「父」模塊。我還沒有見過類似的東西,但是從父類繼承方法的非類模塊似乎有點奇怪。讓我想知道它是否有很好的用處...... – 2009-10-27 23:29:08

+2

@Robert P:有一個父類模塊中的靜態類函數肯定有很好的用處。例如我今天寫了一個緩存處理程序家族,其中子項中的靜態函數包含一些配置信息,這些配置信息需要增加父項中的某些行爲。 – Ether 2009-10-28 01:04:01

1

有調用靜態函數方式主要有三種:

  • $object->static_method()
  • Classname->static_method()
  • Classname::static_method()

你可以定義你的函數是這樣的:

# callable as $object->static_method() or Classname->static_method() 
sub static_method 
{ 
    my $class = shift; # ignore; not needed 
    # ... 
} 

或類似這樣的,這在所有三個調用場景的作品,而不會產生對來電者的側像羅伯特·普的解決方案的任何開銷的作用:

use UNIVERSAL qw(isa); 

sub static_method 
{ 
    my $class = shift if $_[0] and isa($_[0], __PACKAGE__); 
    # ... 
} 
5

與Perl一樣,there is more than one way to do it

use strict; 
use warnings; 
{ 
    package Test::Class; 
    sub static_method{ print join(' ', @_), "\n" } 
} 
  • 您可以使用特殊%::變量來訪問符號表。

    my $class = 'Test::Class'; 
    my @depth = split '::', $class; 
    
    my $ref = \%::; 
    $ref = $glob->{$_.'::'} for @depth; # $::{'Test::'}{'Class::'} 
    
    $code = $glob->{'static_method'}; 
    $code->('Hello','World'); 
    
  • 您可以只使用一個symbolic reference;

    no strict 'refs'; 
    my $code = &{"${class}::static_method"}; 
    # or 
    my $code = *{"${class}::static_method"}{CODE}; 
    $code->('Hello','World'); 
    
  • 您還可以使用字符串eval

    eval "${class}::static_method('Hello','World')"; 
    
  • 在這種情況下,簡單地說,是使用UNIVERSAL::can

    $code = $class->can('static_method'); 
    $code->('Hello','World'); 
    
相關問題