在處理各種獲取和設定引數的網路處理程式中,我大量使用閉包。我有一個子例程,它接收一個閉包并使用在回傳時作為引數傳遞的另一個閉包構建另一個閉包(聽起來很復雜,但這正是我想要這樣的原因)。現在我有一個案例,我必須傳遞兩個非常相似的閉包,每個閉包都使用相同的物件方法,但引數不同(物件方法檢查傳遞的引數數量)。
我的想法不是傳遞兩個(或更多)相似的閉包,而是傳遞$meth_ref對物件方法的參考(物件也傳遞給回傳閉包的函式),以便函式可以使用代碼參考來傳遞不同的引數。
不幸的是,我沒有找到這樣做的語法。
代碼草圖:
sub closure_maker($$)
{
my ($obj, $meth_ref) = @_;
return sub (...) {
$meth_ref->($obj);
...
$meth_ref->($obj, ...);
};
}
my @handlers = (closure_maker($obj1, ???), closure_maker($obj2, ???));
我希望你能明白。
uj5u.com熱心網友回復:
使用$obj->$method_name().
sub closure_maker($$)
{
my ($obj, $method_name) = @_;
return sub {
$obj->$method_name();
...
$obj->$method_name(...);
};
}
my @handlers = map { closure_maker($_, "method_name") } $obj1, $obj2;
您可以使用$obj->can來獲取對該方法的參考。
sub closure_maker($$)
{
my ($obj, $method_name) = @_;
my $method_ref = $obj->can($method_name);
return sub {
$obj->$method_ref();
...
$obj->$method_ref(...);
};
}
uj5u.com熱心網友回復:
您可以獲得對方法的參考,\&Classname::method然后可以將其與該類的給定物件一起使用。例如:
#!/usr/bin/env perl
use strict;
use warnings;
use feature qw/say/;
package Example {
sub new {
my ($class, $name) = @_;
return bless { name => $name }, $class;
}
sub method1 {
my $self = shift;
say "Method 1 of $self->{name}: @_";
}
};
sub make_closure($$) {
my ($obj, $method) = @_;
return sub { $obj->$method(@_); }
}
my $obj1 = Example->new("Bob");
my $obj2 = Example->new("Cindy");
my $closure1 = make_closure($obj1, \&Example::method1);
my $closure2 = make_closure($obj2, \&Example::method1);
$closure1->(qw/1 2/);
$closure2->(qw/A B C/);
輸出
Method 1 of Bob: 1 2
Method 1 of Cindy: A B C
如果您是偏執狂,您可能希望在方法中添加型別檢查,以確保它們不會被錯誤類的物件意外呼叫。isaperl 5.32 中添加的運算子使這變得簡單:
# In package Example
use Carp;
sub method1 {
use experimental qw/isa/;
my $self = shift;
croak "Invalid object; should be an Example" unless $self isa Example;
say "Method 1 of $self->{name}: @_";
}
舊版本可以使用內置isa方法:
# In package Example
use Carp;
use Scalar::Util qw/blessed/;
sub method1 {
my $self = shift;
croak "Invalid object; should be an Example"
unless defined blessed $self && $self->isa("Example");
say "Method 1 of $self->{name}: @_";
}
uj5u.com熱心網友回復:
我找到了一個非常丑陋的解決方案,但它確實有效。示例會話來自真實代碼:
### this is the sample method:
DB<5> x MessageLogFormat::log_appname($log_format)
0 ''
DB<11> $xxxx = \&{*{MessageLogFormat::log_appname}}
DB<12> x ref $xxxx
0 'CODE'
DB<13> x $xxxx->($log_format)
0 ''
DB<14> x $xxxx->($log_format, 1)
0 1
### NAME() just outputs the name of the class
DB<17> $n = $log_format->NAME()
DB<19> $xxx = \&{*{${n}.'::log_appname'}}
### the method is actually a closure (provided by class `Class`) by itself
DB<20> x $xxx
0 CODE(0x1af8960)
-> &Class::__ANON__[lib/Class.pm:85] in lib/Class.pm:78-85
DB<21> x $xxx->($log_format)
0 1
DB<22> x $xxx->($log_format, 0)
0 ''
DB<23> x $xxx->($log_format)
0 ''
### So that worked; try a non-closure method, too:
DB<24> $xxx = \&{*{${n}.'::new'}}
DB<25> x $xxx
0 CODE(0x1afcb88)
-> &MessageLogFormat::new in lib/MessageLogFormat.pm:85-91
在草擬的解決方案中,我不必知道(并明確寫下)正在使用的每個物件的類。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/464294.html
