10

if elsif elsif else因子変数に基づいて決定を下す同じテンプレートを持つPerlサブローチンの束を構築したいと思います。サブルーチンテンプレートの例を次に示します。

sub get_age{

  my $factor=shift;

  if    ($factor == 1 ){ print "do something" }
  elsif ($factor == 2 ){ print "do somthing2" }
  elsif ($factor == 3 ){ print "do somthing3" }
  elsif ($factor == 4 ){ print "do somthing4" }
  else                 { print "error"        }
  }

if else条件の一部を変更したり削除したりする必要がある場合は特に、将来的に保守しやすい、よりエレガントなソリューションに条件を置き換えるためのデザインパターンがPerlにあるのではないかと思います。

4

7 に答える 7

10

何人かの人々がディスパッチテーブルについて言及しました。2つのことがあり、時々それらを離しておくのはいいことです。起こりうる可能性のあるものと、それらを引き起こすもののリストがあります。2つを組み合わせると、ソリューションに固執します。それらを別々に保つと、後で柔軟性が高まります。

ディスパッチテーブルは、動作をプログラム構造ではなくデータとして指定します。これを行うには2つの異なる方法があります。あなたの例では、整数があり、そのようなものは配列を使用して物を格納する可能性があります。ハッシュの例は同じアイデアですが、動作の検索方法が少し異なります。

また、を除外していることに注意してprintください。そのようなコードを繰り返した場合は、繰り返したものを1レベル上に移動してみてください。

use v5.10;

foreach my $factor ( map { int rand 5 } 0 .. 9 ) {
    say get_age_array( $factor );
    }

my @animals = qw( cat dog bird frog );
foreach my $factor ( map { $animals[ rand @animals ] } 0 .. 9 ) {
    say get_age_hash( $factor );
    }

sub get_age_array {
    my $factor = shift;

    state $dispatch = [
        sub { 'Nothing!' }, # index 0
        sub { "Calling 1" },
        sub { 1 + 1 },
        sub { "Called 3" },
        sub { time },
        ];

    return unless int $factor <= $#$dispatch;

    $dispatch->[$factor]->();   
    }


sub get_age_hash {
    my $factor = shift;

    state $dispatch = {
        'cat'  => sub { "Called cat" },
        'dog'  => sub { "Calling 1"  },
        'bird' => sub { "Calling 2, with extra" },
        };

    return unless exists $dispatch->{$factor};

    $dispatch->{$factor}->();   
    }
于 2011-11-29T22:33:59.440 に答える
7

更新:以下のブライアンのコメントを必ず読んでください。基本的に、彼がリンクでコメントしているさまざまな問題があるため、forの代わりに使用することをお勧めします。given私は彼の改善を組み込むために私のアドバイスを更新しました。彼はそれをgiven()の代わりにUse for()で概説しています:

perl 5.10以降given/whenを使用している場合は、探している魔法のペアですが、実際にはfor/when代わりに使用する必要があります。例を次に示します。

use strict;
use warnings;
use feature qw(switch say);

print 'Enter your grade: ';
chomp( my $grade = <> );

for ($grade) {
    when ('A') { say 'Well done!'       }
    when ('B') { say 'Try harder!'      }
    when ('C') { say 'You need help!!!' }
    default { say 'You are just making it up!' }
}
于 2011-11-29T22:13:22.377 に答える
3

物事を短くするだけです:

sub get_age1 {
    my $age = shift;
    $age == 1 ? print "do something" :
    $age == 2 ? print "do somthing2" :
    $age == 3 ? print "do somthing3" :
    $age == 4 ? print "do somthing4" :
                print "error"
}

これは、条件を正規表現として最もよく表現できる場合に、より意味があります。

sub get_age2 {    
    for (shift) { 
        if    (/^ 1 $/x) {print "do something"}
        elsif (/^ 2 $/x) {print "do somthing2"}
        elsif (/^ 3 $/x) {print "do somthing3"}
        elsif (/^ 4 $/x) {print "do somthing4"}
        else             {print "error"       }
    }
}

ここにいくつかのディスパッチテーブルがあります:

単純なもの(バグあり):

{
    my %age = ( # defined at runtime
        1 => sub {print "do something"},
        2 => sub {print "do somthing2"},
        3 => sub {print "do somthing3"},
        4 => sub {print "do somthing4"},
    );
    # unsafe to call get_age3() before sub definition
    sub get_age3 {
        ($age{$_[0]} or sub {print "error"})->()
    }
}

より良いもの:

{
    my %age;
    BEGIN {
        %age = ( # defined at compile time
            1 => sub {print "do something"},
            2 => sub {print "do somthing2"},
            3 => sub {print "do somthing3"},
            4 => sub {print "do somthing4"},
        )
    }
    # safe to call get_age4() before sub definition
    sub get_age4 {
        ($age{$_[0]} or sub {print "error"})->()
    }
}

それを書く別の方法:

BEGIN {
    my %age = ( # defined at compile time
        1 => sub {print "do something"},
        2 => sub {print "do somthing2"},
        3 => sub {print "do somthing3"},
        4 => sub {print "do somthing4"},
    );
    # safe to call get_age5() before sub definition
    sub get_age5 {
        ($age{$_[0]} or sub {print "error"})->()
    }
}

それを書く別の良い方法:

{
    my $age;
    # safe to call get_age6() before sub definition
    sub get_age6 {
        $age ||= { # defined once when first called
           1 => sub {print "do something"},
           2 => sub {print "do somthing2"},
           3 => sub {print "do somthing3"},
           4 => sub {print "do somthing4"},
        };
        ($$age{$_[0]} or sub {print "error"})->()
    }
}
于 2011-11-30T02:09:49.290 に答える
0

Dispatch tables are a perfect fit for this type of design pattern. I've used this idiom many times. Something like this:

sub get_age {
    my $facter = shift;
    my %lookup_map = (
        1 => sub {.....},
        2 => sub {.....},
        3 => \&some_other_sub,
        default => \&some_default_sub,
    );
    my $code_ref = $lookup_map{$facter} || $lookup_map{default};
    my $return_value = $code_ref->();
    return $return_value;
}

This works when the argument you are using to determine which case gets executed is going to exist as a key in your hash table. If it is possible that it won't be an exact match then you may need to use regular expressions or some other way to match your input to which bit of code to execute. You can use regexes as hash keys like this:

my %patterns = (
    qr{^/this/one}i => sub {....},
    qr{^/that/one}is => sub {....},
    qr{some-other-match/\d+}i => \&some_other_match,
)
my $code_ref;
for my $regex (keys %patterns) {
    if ($facter =~ $regex) {
        $code_ref = $patterns{$regex};
        last;
    }
}
$code_ref ||= \&default_code_ref;
$code_ref->();
于 2011-11-29T22:47:25.783 に答える
0

examples / reference/dispatch_table.plを参照してください

https://code-maven.com/slides/perl/dispatch-table

#!/usr/bin/perl
use strict;
use warnings;

# Use subroutine references in a hash to define what to do for each case

my %dispatch_table = (
    '+' => \&add,
    '*' => \&multiply,
    '3' => \&do_something_3,
    '4' => \&do_something_4,
);

foreach my $operation ('+', 'blabla', 'foobar', '*'){
    $dispatch_table{$operation}->(
        var1 => 5,
        var2 => 7,
        var3 => 9,                       
    ) if ( exists $dispatch_table{$operation} );
}

sub add {
    my %args = (@_);
    my $var1 = $args{var1}; 
    my $var2 = $args{var2};

    my $sum = $var1 + $var2;
    print "sum = $sum \n";
    return;
}

sub multiply {
    my %args = (@_);
    my $var1 = $args{var1}; 
    my $var3 = $args{var3};

    my $mult = $var1 * $var3;
    print "mult = $mult \n";
    return;
}

出力:

sum = 12 
mult = 45 
于 2020-09-13T12:25:45.313 に答える
-1

これは、ディスパッチテーブルのようなもののための場所かもしれません。私は自分でそれをしていませんが、このページは始まりかもしれません:http ://www.perlmonks.org/?node_id=456530

于 2011-11-29T22:14:59.790 に答える
-4

Switchを使用します;

高次Perlのディスパッチテーブルを読んでください。

于 2011-11-29T22:14:49.013 に答える