想象一下,我有这个Perl脚本
my $name = " foo ";
my $sn = " foosu";
trim($name, \$sn);
print "name: [$name]\n";
print "sn: [$sn]\n";
exit 0;
sub trim{
my $fref_trim = sub{
my ($ref_input) = @_;
${$ref_input} =~ s/^\s+// ;
${$ref_input} =~ s/\s+$// ;
};
foreach my $input (@_){
if (ref($input) eq "SCALAR"){
$fref_trim->($input);
} else {
$fref_trim->(\$input);
}
}
}
结果:
name: [foo]
sn: [foosu]
我希望$ name是" [ foo ]
"在调用trim
后打印值时,sub会按照我的意愿设置$name
。为什么这个工作,当它真的不应该?
我没有通过引用传递$ name,而trim
sub没有返回任何内容。我希望trim
子要创建$name
值的副本,处理副本,但原始$name
在打印时仍会有前导和尾随空格在主要代码中。
我认为这是因为@_
的别名,但是foreach my $input (@_)
不应该强制sub复制值,只处理值而不是别名?
我知道我可以简化这个子,我只用它作为例子。
答案 0 :(得分:8)
@_
的元素是原始变量的别名。您所观察到的是:
sub ltrim {
$_[0] =~ s/^\s+//;
return $_[0];
}
和
sub ltrim {
my ($s) = @_;
$s =~ s/^\s+//;
return $s;
}
将您的代码与以下内容进行比较:
#!/usr/bin/env perl
my $name = " foo ";
my $sn = " foosu";
trim($name, \$sn);
print "name: [$name]\n";
print "sn: [$sn]\n";
sub trim {
my @args = @_;
my $fref_trim = sub{
my ($ref_input) = @_;
${$ref_input} =~ s/^\s+//;
${$ref_input} =~ s/\s+\z//;
};
for my $input (@args) {
if (ref($input) eq "SCALAR") {
$fref_trim->($input);
}
else {
$fref_trim->(\$input);
}
}
}
输出:
$ ./zz.pl
name: [ foo ]
sn: [foosu]
另请注意,for my $input ( @array )
中的循环变量不会为数组的每个元素创建新副本。见perldoc perlsyn
:
foreach
循环遍历正常列表值,并将标量变量VAR
依次设置为列表的每个元素。 ......
foreach
循环索引变量是您要循环的列表中每个项目的隐式别名。
在您的情况下,这意味着,在每次迭代时$input
都是@_
的对应元素的别名,@_
本身是作为参数传递给变量的变量的别名。子程序。
复制sub trim {
my $fref_trim = sub{
my ($ref_input) = @_;
${$ref_input} =~ s/^\s+//;
${$ref_input} =~ s/\s+\z//;
};
for my $input (@_) {
my $input_copy = $input;
if (ref($input_copy) eq "SCALAR") {
$fref_trim->($input_copy);
}
else {
$fref_trim->(\$input_copy);
}
}
}
可以防止修改调用上下文中的变量。当然,你可以这样做:
@_
但我觉得如果你不想做出选择性的话,我会发现isArray
的批发副本一次更清晰,更有效率。
答案 1 :(得分:3)
我认为这是因为
@_
的别名,但是foreach my $input (@_)
不应该强制sub复制值,只处理值而不是别名?
你是对的,@_
包含别名。缺少的部分是foreach
也将循环变量别名化为当前列表元素。引用perldoc perlsyn
:
如果LIST的任何元素是左值,您可以通过修改循环内的VAR来修改它。相反,如果LIST的任何元素不是左值,则任何修改该元素的尝试都将失败。换句话说,
foreach
循环索引变量是列表中您要循环的每个项的隐式别名。
所以最终$input
是$_[0]
的别名,这是$name
的别名,这就是为什么您会看到$name
中出现的更改。