没有辅助变量的间接方法调用

时间:2013-11-24 15:54:18

标签: perl

有这个有效的短代码

use 5.014;
package Module;
use warnings;
use Moose;
use Method::Signatures::Simple;

has 'commands' => (
    is => 'ro',
    isa => 'HashRef',
    default => sub{{
        open   => 'my_open',
        close  => 'my_close',
    }},
);

method run($cmd, $args) {
    my $met = $self->commands->{$cmd} if exists $self->commands->{$cmd};
    $self->$met($args) if $met;

    #-----
    #how to write the above two lines in one command?
    #the next doesn't works
    # $self->commands->{$cmd}($args) if exists $self->commands->{$cmd};
    #-----
}

method my_open { say "module: open" }
method my_close { say "module: close" }

package main;
my $ef = Module->new();
$ef->run('open');

主要问题在于代码 - 如何在一行中编写“run”方法 - 没有辅助变量$met

并且,这是更好的方法来执行上述方案 - 所以基于输入调用方法?

1 个答案:

答案 0 :(得分:4)

首先,请不要my $foo = $x if $y。您会遇到意外和未定义的行为,因此最好避免使用该语法。

这段代码

my $met = $self->commands->{$cmd} if exists $self->commands->{$cmd};
$self->$met($args) if $met;

相当于

if (my $met = $self->commands->{$cmd}) {
  $self->$met($args);
}

因为exists测试在这里是多余的(如果条目存在,则条目只能为真)。

如果我们不想引入另一个变量,我们有两个选择:

  1. 使用$_

    $_ and $self->$_($args) for $self->commands->{$cmd};
    

    这不会将for用作循环,而是用作局部化器。

  2. 使用标量引用:

    $self->${\( $self->commands->{$cmd} )}($args) if $self->commands->{$cmd};
    

    $self->${\( $self->commands->{$cmd} || "no_op" )}($args);
    
    ...
    
    method no_op { }
    

    不要做这样的事情,因为无法读取线路噪音。

  3. 这些都不是特别优雅,最好使用我上面展示的清理过的解决方案。

    仅仅因为可以在一行中完成,并不意味着应该完成。 “这是Perl,而不是 ......哦,没关系。”