如何将if / else更改为哈希函数?佩尔

时间:2018-07-21 03:12:05

标签: perl

sub funcA{
    my ($A) = @_;  <--require 1
}
sub funcB{
    my ($A, $B) = @_;  <--require 2
}
sub funcC{
    my ($A, $B, $C) = @_;  <--require 3
}

sub funcRun{
    my ($param) = @_;
    my $other1, $other2, $other3;  <--will be assigned at ',,,,,'

    ,,,,,

    if($param eq 'a'){
        funcA, $other1;
        return;
    }elsif($param eq = 'b'){
        funcB, $other1, $other2;
        return;
    }elsif($param eq = 'c'){
        funcC, $other1, $other2, $other3;
        return;
    }
}

我想将此更改为下一个代码

sub funcA{
    my ($A) = @_;  #<--require 1
}
sub funcB{
    my ($A, $B) = @_;  #<--require 2
}
sub funcC{
    my ($A, $B, $C) = @_;  #<--require 3
}

my $hash_ref = {
    'a' => \&funcA,
    'b' => \&funcB,
    'c' => \&funcC
}

sub funcRun{
    my ($param) = @_;
    my $other1, $other2, $other3;  #<--will be assigned at ',,,,,'

    ,,,,,

    $hash_ref->{$param}(ARGUMENTS);   #<--my problem

}

但是我不知道如何制作包含可变数量参数的 ARGUMENTS 部分。 我认为每个函数都是在 funcRun 代码中定义的,但是我不知道if / else代码的区别。而且我听说从某人开始依次传递3个参数值并接受参数是不好的

2 个答案:

答案 0 :(得分:3)

在澄清后进行了更新。最后一个代码段可能正是所要求的。


在运行时生成的列表中,参数决定使用哪个参数集的设计给您带来了麻烦;情况很复杂。不知道实际的问题,我不知道还能提供什么(除了猜测)。也许要弄清用法?

已经说过,一种完成所需内容的方法是在hashref中存储与函数一起使用的参数的规范以及函数名称。另一个可能是要有一个单独的结构,并为每个参数设置参数集。

例如

use warnings;
use strict;
use feature 'say';

my $dispatch = { 
    'a' => { name => \&funcA, lastidx => 0 },
    'b' => { name => \&funcB, lastidx => 1 },
    'c' => { name => \&funcC, lastidx => 2 } 
};

funcRun($_)  for qw(a b c);

sub funcRun {
    my ($param) = @_; 
    my @args = qw(one two three);

    my $func    = $dispatch->{$param}{name};
    my $lastidx = $dispatch->{$param}{lastidx};

    $func->( @args[0..$lastidx] );
}

sub funcA { say "@_" }
sub funcB { say "@_" }
sub funcC { say "@_" }

如果确实需要从列表中选择位置的参数,则使用数组。 印刷品

one
one two
one two three

但是,我建议您澄清一下它的用途,以便我们提供更简单的设计。


在评论中进行解释之后,我最初以为是偶然的,实际上可能会有所帮助。

如果函数funcA实际上仅采用第一个参数,funcB的前两个参数和funcC的所有三个参数(在运行时生成的列表中),那么可以很好地将所有参数传递给全部

$func->( @args );

sub funcA {
    my ($A) = @_;  # arguments other than the first are discarded
    ...
}

每个函数都需要它,其余的参数都被丢弃。

此外,如果函数以某种方式知道要采用给定参数列表中的哪一个,则只需再次传递所有参数即可。然后他们可以按位置选择他们的论点

sub funcB {
    my ($A, undef, $B) = @_;  # if it needs first and third
    ...
}

或通过命名键

# Work out what arguments are for which function
my $args = { for_A => ..., for_B => ..., for_C => ... };
...
$func->( $args );

sub funcA {
    my ($args) = @_
    my $A = $args->{for_A};
    ...
}

现在参数需要存储在哈希中。

最后也是最好的选择,可以在通话前解决所有问题

my $dispatch = { a => \&funcA, b => \&funcB, c => \&funcC };

funcRun($_)  for qw(a b c);

sub funcRun {
    my ($param) = @_;
    # Work out arguments for functions
    my $args = { a => ..., b => ..., c => ... };      

    $dispatch->{$param}->( $args->{$param} );
}

# subs funcA, funcB, funcC are the same   

需要对代码进行最少的更改(只需将参数存储在哈希中)。

函数和调度表都不需要了解可能的参数列表,所有这些都在funcRun中解决。这样可以避免函数与外部代码纠缠在一起。

答案 1 :(得分:2)

您的问题源于您要从任意,不相关的变量中传递值的选择这一事实。因此,解决方案是将您可能希望传递给子例程的所有数据放在单个数据结构中,并定义一种机制来为每个调用提取正确的数据。您已经有一个为此使用数组的解决方案,但我认为在哈希中更容易理解。

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

sub funcA{
    my ($A) = @_;
    say $A;
}
sub funcB{
    my ($A, $B) = @_;
    say "$A / $B";
}
sub funcC{
    my ($A, $B, $C) = @_;
    say "$A / $B / $C";
}

my $hash_ref = {
    'a' => { func => \&funcA, args => [ qw[ other1 ] ] },
    'b' => { func => \&funcB, args => [ qw[ other1 other2 ] ] },
    'c' => { func => \&funcC, args => [ qw[ other1 other2 other3 ] ] },
};

sub funcRun{
    my ($param) = @_;

    my %args = (
        other1 => 'foo',
        other2 => 'bar',
        other3 => 'baz',
    );

    # $hash_ref->{$param}{args} is an array reference containing
    # the names of the arguments you need.
    # @{ ... } turns that array reference into an array.
    # @args{ ... } uses that array to look up those keys in the
    # %args hash (this is called a hash slice)

    $hash_ref->{$param}{func}(@args{ @{ $hash_ref->{$param}{args} } });

}

funcRun($_) for qw[a b c];

但是,说实话,将数据存储在哈希中,这只是将整个哈希传递到每个子例程中并让他们确定要使用哪些数据的一小步。甚至将您的哈希变成一个对象。