在对各种事件作出反应的 Perl 守护程序中,我试图通过创建匿名子例程在 2 种情况下使用Null 对象模式,它应该只返回一个值 1 aka “true”(请滚动到右侧查看检查子例程LOGIN和ALIVE事件):
package User;
our %EVENTS = (
LOGIN => {handler => \&handleLogin, check => sub {1}, },
CHAT => {handler => \&handleChat, check => \&mayChat, },
JOIN => {handler => \&handleJoin, check => \&mayJoin, },
LEAVE => {handler => \&handleLeave, check => \&mayLeave, },
ALIVE => {handler => sub {}, check => sub {1}, },
BID => {handler => \&handleBid, check => \&checkArgs, },
TAKE => {handler => \&handleTake, check => \&checkArgs, },
# .... more events ....
);
sub action($$$) {
my $user = shift;
my $event = shift;
my $arg = shift;
my $game = $user->{GAME};
unless (exists $EVENTS{$event}) {
print STDERR "wrong event: $event\n";
return;
}
my $handler = $EVENTS{$event}->{handler};
my $check = $EVENTS{$event}->{check};
return unless $user->$check->($arg); # XXX fails
$user->$handler->($arg);
}
sub mayChat($$) {
my $user = shift;
return if $user->{KIBITZER};
}
# ...... more methods here ...
1;
不幸的是,我收到了LOGIN事件的运行时错误:
Can't use string ("1") as a subroutine ref while "strict refs" in use
有人知道如何在这里解决吗?
如何为匿名 Perl 子例程提供“函数指针”?
处理程序 => \&sub { 1 }也不这样做。
在 CentOS 5.x 和 6.x 上使用 perl 5.8.8 和 perl 5.10.1
更新:
我也试过以下:
my $check = $EVENTS{$event}->{check};
return unless $check->($user, $arg);
但这无济于事。我认为这排除了某些答案中建议的“缺失的祝福”。
更新 2:
我在原始问题中扩展了源代码片段。背景是:我正在重构我的源代码,因此我已经创建了上面列出的%EVENTS哈希,因此对于每个传入事件(从Flash 客户端通过 TCP-socket 发送的字符串)那里是对验证事件的子例程 ( check ) 的引用和对执行某些操作的另一个子例程 ( handler ) 的引用。我不确定其他子程序是否有效 - 我已经被第一个LOGIN 事件困住了。
我也不明白为什么不检查 => sub { 1 }上面的工作 - sub不应该返回对匿名子例程的引用(当名称被省略时 - 根据perldoc perlref第 4 节)?
更新 3:
打印 Dumper(\%EVENTS)的输出-
$VAR1 = {
'PLAY' => {
'check' => sub { "DUMMY" },
'handler' => sub { "DUMMY" },
},
'JOIN' => {
'check' => sub { "DUMMY" },
'handler' => sub { "DUMMY" },
},
'OVER1' => {
'check' => sub { "DUMMY" },
'handler' => sub { "DUMMY" },
},
'ALIVE' => {
'check' => sub { "DUMMY" },
'handler' => sub { "DUMMY" },
},
'DISCARD' => {
'check' => $VAR1->{'PLAY'}{'check'},
'handler' => sub { "DUMMY" },
},
'MISS1' => {
'check' => sub { "DUMMY" },
'handler' => sub { "DUMMY" },
},
'LOGIN' => {
'check' => sub { "DUMMY" },
'handler' => sub { "DUMMY" },
},
'TAKE' => {
'check' => $VAR1->{'PLAY'}{'check'},
'handler' => sub { "DUMMY" },
},
'ONEMORE' => {
'check' => sub { "DUMMY" },
'handler' => sub { "DUMMY" },
},
'OVER2' => {
'check' => sub { "DUMMY" },
'handler' => sub { "DUMMY" },
},
'MISS2' => {
'check' => sub { "DUMMY" },
'handler' => sub { "DUMMY" },
},
'EXACT' => {
'check' => sub { "DUMMY" },
'handler' => sub { "DUMMY" },
},
'TRUST' => {
'check' => $VAR1->{'PLAY'}{'check'},
'handler' => sub { "DUMMY" },
},
'LEAVE' => {
'check' => sub { "DUMMY" },
'handler' => sub { "DUMMY" },
},
'DEFEND' => {
'check' => $VAR1->{'PLAY'}{'check'},
'handler' => sub { "DUMMY" },
},
'OPEN' => {
'check' => $VAR1->{'PLAY'}{'check'},
'handler' => sub { "DUMMY" },
},
'REVEAL' => {
'check' => sub { "DUMMY" },
'handler' => sub { "DUMMY" },
},
'CHAT' => {
'check' => sub { "DUMMY" },
'handler' => sub { "DUMMY" },
},
'DECLARE' => {
'check' => $VAR1->{'PLAY'}{'check'},
'handler' => sub { "DUMMY" },
},
'BACK' => {
'check' => sub { "DUMMY" },
'handler' => sub { "DUMMY" },
},
'MISERE' => {
'check' => sub { "DUMMY" },
'handler' => sub { "DUMMY" },
},
'BID' => {
'check' => $VAR1->{'PLAY'}{'check'},
'handler' => sub { "DUMMY" },
}
};