2012-01-25 3 views
8

Я это trim рутина:

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

Он обрезает пробелы «на месте», то есть:

trim $x, $y; 

обрезает пробелы в $ х и $ y (изменение их).

Как я могу улучшить trim так, что это позволяет мне назвать это нравится:

trim; 

, и это будет такой же, как:

trim $_; 

?

ответ

11

Все, что вам нужно сделать, это заменить @_ с @_ ? @_ : $_ в аргументе к петле for ,

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

За ответ Ikegami, есть нытье вопрос о том, что делать фитофтороз что лексическая $_ (объявленный с my $_;), так что версия $_ не является глобальной, но привязан к лексической площадке ,

(_) прототипа является одним из способов решить эту проблему, но это также означает, что подпрограмма принимает только один аргумент, и что аргумент имеет скалярный контекст, что делает его столь же плохо, как ($) прототипа (в связи с непредвиденными последствиями скалярного контекста).

При попытке сделать магию на лексике, модуль 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]" 

Лично я просто избежать лексических $_ и уродливые проблемы, как это просто исчезают. Но если вам нужно его поддержать, это путь.

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! 
4

Если ваш trim просто взял один аргумент, вы можете использовать прототип _.

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

Тогда все это будет работать:

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

Но поскольку ваш trim принимает список аргументов, вы не можете использовать _ прототип. Вы должны использовать @_ ? @_ : $_.

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; } 
+4

В re lexical '$ _': не делайте этого. :) – tchrist

+2

@tchrist, так что не используйте 'given', затем ...? – ikegami

+0

'sub trim (_ @) {...}' –