使用@_中的元素引用来避免重复代码

时间:2015-08-08 20:55:49

标签: perl

在子例程中引用@_的元素以避免重复代码是否安全?我也想知道以下是好的做法还是可以简化。我有一个子例程mod_str,它接受​​一个选项,说明是否应该就地修改字符串参数:

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

my $str = 'abc';

my $mstr = mod_str( $str, in_place => 0 );
say $mstr;
mod_str( $str, in_place => 1 );
say $str;

sub mod_str {
    my %opt;
    %opt = @_[1..$#_];

    if ( $opt{in_place} ) {
        $_[0] =~ s/a/A/g;
        # .. do more stuff with $_[0]
        return;
    }
    else {
        my $str = $_[0];
        $str =~ s/a/A/g;
        # .. do more stuff with $str
        return $str;
    }
}

为避免重复/重复上述ifelse块中的代码,我尝试改进mod_str

sub mod_str {
    my %opt;
    %opt = @_[1..$#_];

    my $ref;
    my $str;
    if ( $opt{in_place} ) {
        $ref = \$_[0];
    }
    else {
        $str = $_[0];  # make copy
        $ref = \$str;
    }
    $$ref =~ s/a/A/g;
    # .. do more stuff with $$ref
    $opt{in_place} ? return : return $$ref;
}

2 个答案:

答案 0 :(得分:8)

"到位" flag将函数的接口更改为应该是新函数的点。它将简化界面,测试,文档和内部功能,以实现两个功能。用户已经为您做出了这样的选择,而不是必须解析参数并拥有一个大的if / else块。

另一种看待它的方法是in_place选项将始终设置为常量。因为它从根本上改变了函数的行为方式,所以没有明智的案例可以写in_place => $flag

一旦你这样做,重用变得更加明显。编写一个函数来执行操作。写另一个在副本上调用它。

sub mod_str_in_place {
    # ...Do work on $_[0]...

    return;
}

sub mod_str {
    my $str = $_[0];  # string is copied

    mod_str_in_place($str);

    return $str;
}

答案 1 :(得分:5)

在没有耻辱given的情况下,我喜欢使用for作为主题。这有效地将$_别名为$_[0]或本地副本,具体取决于in_place哈希元素的值。它可以与您的$ref直接比较,但使用别名,更清晰

我认为没有理由在字符串被修改的情况下返回无用的undef / ();子例程也可以返回字符串的新值。 (我怀疑旧的值可能更有用,以$x++的方式出现,但这会产生更丑陋的代码!)

我不确定这是否是除了我之外的任何人都可读的代码,所以欢迎提出意见!

use strict;
use warnings;

my $ss = 'abcabc';
printf "%s %s\n", mod_str($ss), $ss;

$ss = 'abcabc';
printf "%s %s\n", mod_str($ss, in_place => 1), $ss;

sub mod_str {

    my ($copy, %opt) = @_;

    for ( $opt{in_place} ? $_[0] : $copy ) {
        s/a/A/g;
        # .. do more stuff with $_
        return $_;
    }
}

输出

AbcAbc abcabc
AbcAbc AbcAbc