如果没有指定参数,则修改$ _

时间:2012-01-25 23:56:22

标签: perl

我有trim例程:

sub trim {
    for (@_) {
        s|^\s+||;
        s|\s+$||;
    }
}

它修剪空白"就地",即:

trim $x, $y;

将修剪$ x和$ y的空白(修改它们)。

如何改进trim,以便我可以将其称为:

trim;

,这将与:

相同
trim $_;

3 个答案:

答案 0 :(得分:11)

只需检查是否没有提供参数:

use strict;
use warnings;

$_=" abc ";

sub trim
{
    if(@_)
    {
        foreach my $i(@_)
        {
            $i=~s/^\s+//;
            $i=~s/\s+$//;
        }
    }
    else
    {
        s/^\s+//;
        s/\s+$//;
    }
}

trim;

print "!$_!\n"; #Throwing in exclamation points just to make sure white space is gone.

这会产生输出

!abc!

答案 1 :(得分:11)

您需要做的就是在@_循环的参数中将@_ ? @_ : $_替换为for

sub trim {
    for (@_ ? @_ : $_) {
        s|^\s+||;
        s|\s+$||;
    }
}

根据ikegami的回答,关于如何处理词汇$_(用my $_;声明)的问题有一个唠叨的问题,因为$_版本不是全局的,但是绑在一个词汇垫上。

(_)原型是解决这个问题的一种方法,但它也意味着子程序只接受一个参数,并且参数具有标量上下文,这使得它与{{1}一样糟糕原型(由于标量上下文的意外后果)。

每当试图在词汇上做魔术时,模块PadWalker就派上用场了。所以这是一个在列表上正常工作的版本,适用于词法和全局($),并且它不会在调用站点上强制使用标量上下文:

$_

就个人而言,我只是避免使用词汇use PadWalker 'peek_my'; sub trim { my $it; unless (@_) { my $pad = peek_my 1; $it = $$pad{'$_'} || \$::_ } for (@_ ? @_ : $$it) { s/^\s+//; s/\s+$//; } } {local $_ = " a "; trim; say "[$_]"} # prints "[a]" {my $_ = " a "; trim; say "[$_]"} # prints "[a]" {my $x = " a "; trim $x; say "[$x]"} # prints "[a]" ,这样的丑陋问题就会消失。但如果你需要支持它,这是一种方式。

答案 2 :(得分:4)

如果您的trim只拿了一个arg,则可以使用_原型。

sub trim(_) {
   for ($_[0]) {
      s|^\s+||;
      s|\s+$||;
   }
}

然后所有这些都可行:

{ local $_ = "  abc  "; trim;    say;    }
{ my    $_ = "  abc  "; trim;    say;    }
{ my    $x = "  abc  "; trim $x; say $x; }

但由于您的trim会获取args列表,因此您无法使用_原型。您必须使用@_ ? @_ : $_

sub trim {
   for (@_ ? @_ : $_) {
      s|^\s+||;
      s|\s+$||;
   }
}

但这意味着它不适用于词汇$_

{ local $_ = "  abc  "; trim;    say;    }
{ my    $_ = "  abc  "; trim;    say;    }  # XXX $::_ changed instead of $_
{ my    $x = "  abc  "; trim $x; say $x; }