是否可以在Perl中動態指定一個類並訪問該類中的靜態方法?這是不行的,但足以說明我想做什麼:我可以在Perl中訪問動態指定類中的靜態方法嗎?
use Test::Class1;
my $class = 'Test::Class1';
$class::static_method();
我知道我能做到這一點:
$class->static_method();
,並忽略傳遞給static_method類的名字,但我不知道是否有一個更好的方法。
是否可以在Perl中動態指定一個類並訪問該類中的靜態方法?這是不行的,但足以說明我想做什麼:我可以在Perl中訪問動態指定類中的靜態方法嗎?
use Test::Class1;
my $class = 'Test::Class1';
$class::static_method();
我知道我能做到這一點:
$class->static_method();
,並忽略傳遞給static_method類的名字,但我不知道是否有一個更好的方法。
我不知道這樣做的特別好的方式,但也有一些不太好的方面,比如這個程序:
#!/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"
。
@Tim我現在明白了。對不起,不必要的編輯。我發佈了一個使用字符串'eval'的解決方案來顯示使用代碼作爲模板的另一種方法。 – 2009-10-27 22:59:08
@Sinan不是問題!讓我有機會進一步解釋並首次使用「回滾」功能。 :-) – Tim 2009-10-27 23:00:22
您可以使用字符串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% --
是!嚴格執行的方法是使用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'can'是imo最不瘋狂的方式。它仍然會導致::不能做的整個繼承事件,但它會讓你繞過整個傳遞的$ self/$ classname作爲$ _ [0]行爲。 – 2009-10-27 23:27:08
至少,如果它是一個模塊,很可能沒有「父」模塊。我還沒有見過類似的東西,但是從父類繼承方法的非類模塊似乎有點奇怪。讓我想知道它是否有很好的用處...... – 2009-10-27 23:29:08
@Robert P:有一個父類模塊中的靜態類函數肯定有很好的用處。例如我今天寫了一個緩存處理程序家族,其中子項中的靜態函數包含一些配置信息,這些配置信息需要增加父項中的某些行爲。 – Ether 2009-10-28 01:04:01
有調用靜態函數方式主要有三種:
$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__);
# ...
}
與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');
Upvoted幫我浪費了15分鐘我的僱主的時間。 :) – Ether 2009-10-27 23:22:02
呃我的意思是花..當然富有成效! – Ether 2009-10-27 23:22:59