非常重要的一部分,其他的答案已經錯過爲該線
grep {s/(\d+)/sprintf"%06.6d",$1/ge,1} @_;
其實就是修改傳遞給函數的參數,而不是它們的副本。
grep
是一個過濾命令,代碼塊內的$_
中的值是@_
中某個值的別名。 @_
又包含傳遞給函數的參數的別名,所以當s///
運算符執行替換時,正在對原始參數進行更改。這顯示在下面的例子:
sub test {grep {s/a/b/g; 1} @_}
my @array = qw(cat bat sat);
my @new = test @array;
say "@new"; # prints "cbt bbt sbt" as it should
say "@array"; # prints "cbt bbt sbt" as well, which is probably an error
你正在尋找(即申請修改$_
到列表的副本的功能)已被封裝在多個模塊的apply
功能的行爲。我的模塊List::Gen包含這樣的實現。 apply
也相當簡單寫自己:
sub apply (&@) {
my ($sub, @ret) = @_;
$sub->() for @ret;
wantarray ? @ret : pop @ret
}
就這樣,你的代碼可以改寫爲:
sub natural_sort {
apply {s/(^|\D)0+(\d)/$1$2/g} sort apply {s/(\d+)/sprintf"%06.6d",$1/ge} @_
}
如果有重複的替代你的目標是執行排序與原始數據的一個短暫的修改應用,你應該看看一個叫做Schwartzian transform的Perl成語,它是實現這個目標的更有效的方式。
測試和工程有關這個主題的相同 – Craig 2011-05-05 09:27:30