在(非常感谢)perlmonks网站上,我发现以下代码片段修剪了字符串两边的空格:
sub trim {
@_ = $_ if not @_ and defined wantarray;
@_ = @_ if defined wantarray;
for (@_ ? @_ : $_) { s/^\s+//, s/\s+$// }
return wantarray ? @_ : $_[0] if defined wantarray;
}
Run Code Online (Sandbox Code Playgroud)
我不明白为什么作者几乎每一行都要检查各种各样的问题.为什么不修剪字符串,让程序员map
在传递数组时使用?
这个修剪之间的区别是什么,如下所示:
my @test_array = ( 'string1', ' string2', 'string3 ', ' string4 ');
my @result = trim(@test_array);
Run Code Online (Sandbox Code Playgroud)
或者一个简单的修剪,当需要修剪数组时称为这样:
my @test_array = ( 'string1', ' string2', 'string3 ', ' string4 ');
my @result = map { trim($_) } @test_array;
Run Code Online (Sandbox Code Playgroud)
Nyl*_*ile 11
首先,如果你抽象出那张地图会更好:
#e.1.
sub trim
{
my @ar = @_;
for (@ar) { s/^\s+//, s/\s+$// };
return wantarray ? @ar : $ar[0];
}
Run Code Online (Sandbox Code Playgroud)
其次,考虑以上示例并将其与以下内容进行比较:
#e.2.
sub trim
{
for (@_) { s/^\s+//, s/\s+$// };
}
Run Code Online (Sandbox Code Playgroud)
有什么不同?
E.1.返回一个新的修剪数组,而e.2.修改原始数组.
好了,原来神秘的子程序做了什么?
它自动神奇(是啊,它的Perl)修改原始数组,如果你没有将返回值赋值给任何东西或保持原始数组不变,并返回一个新的修剪数组,如果你将返回值赋给另一个变量.
怎么样?
通过检查是否完全定义了wantarray.只要函数在右侧并且返回值被赋值给变量"defined wantarray"为真(无论标量/数组上下文如何).
逐行打破这一点,因为它还没有:
sub trim {
@_ = $_ if not @_ and defined wantarray;
# if there are no arguments, but a return value is requested
# then place a copy of $_ into @_ to work on
@_ = @_ if defined wantarray;
# if the caller expects a return value, copy the values in @_ into itself
# (this breaks the aliasing to the caller's variables)
for (@_ ? @_ : $_) { s/^\s+//, s/\s+$// }
# perform the substitution, in place, on either @_ or $_ depending on
# if arguments were passed to the function
return wantarray ? @_ : $_[0] if defined wantarray;
# if called in list context, return @_, otherwise $_[0]
}
Run Code Online (Sandbox Code Playgroud)
我同意代码对所有wantarray
检查都有点乏味,但结果是一个与Perl的内置函数具有一定灵活性的函数.使函数"智能"的最终结果是清理调用站点(避免循环结构,临时变量,重复......),这取决于使用函数的频率,可以有意义地提高代码可读性.
该功能可以简化一点:
sub trim {
@_ = @_ ? @_ : $_ if defined wantarray;
s/^\s+//, s/\s+$// for @_ ? @_ : $_;
wantarray ? @_ : shift
}
Run Code Online (Sandbox Code Playgroud)
前两行可以合并为一行,因为它们@_
只使用不同的源值执行相同的操作(分配).并且最后不需要外部return ... if defined wantarray
检查,因为在void上下文中返回值无论如何都不会做任何事情.
但我可能会改变最后一行,wantarray ? @_ : pop
因为它使它表现得像一个列表(标量上下文中的最后一个元素).
一旦完成所有操作,就可以使用以下调用样式:
my @test_array = ( 'string1', ' string2', 'string3 ', ' string4 ');
my @result = trim @test_array;
my $result = trim $test_array[0];
trim @test_array; # in place trim
Run Code Online (Sandbox Code Playgroud)
甚至还支持呼叫站点循环:
my @result = map trim, @test_array;
Run Code Online (Sandbox Code Playgroud)
或者更详细地说:
my @result = map trim($_), @test_array;
Run Code Online (Sandbox Code Playgroud)
它可以在类似的while循环中使用 chomp
while (<$file_handle>) {
trim;
# do something
}
Run Code Online (Sandbox Code Playgroud)
关于Perl中dwimmery的观点喜忧参半.我个人喜欢它,当函数给我灵活地以一种有意义的方式对调用者进行编码时,而不是解决函数的刚性接口.
可能作者想要模仿标准chomp
函数的行为.您无需在自己的功能中执行此操作.
Run Code Online (Sandbox Code Playgroud)man perlfunc chomp VARIABLE chomp( LIST ) chomp
[...]如果你选择一个列表,每个元素都会被选中.[...]