[英]Perl unexpected result
Imagine I have this Perl script 想象一下,我有这个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);
}
}
}
Result: 结果:
name: [foo]
sn: [foosu]
I would expect $name to be " [ foo ]
" when printing the value after calling trim
, but the sub is setting $name
as I would want it. 在调用trim
之后打印值时,我希望$ name为“ [ foo ]
”,但是sub正在设置$name
因为我想要它。 Why is this working, when it really shouldn't? 为什么这个工作,当它真的不应该?
I'm not passing $name by reference and the trim
sub is not returning anything. 我没有通过引用传递$ name而trim
子没有返回任何东西。 I'd expect the trim
sub to create a copy of the $name
value, process the copy, but then the original $name
would still have the leading and trailing white spaces when printed in the main code. 我希望trim
子创建$name
值的副本,处理副本,但是当在主代码中打印时,原始$name
仍然会有前导和尾随空格。
I assume it is because of the alias with @_
, but shouldn't the foreach my $input (@_)
force the sub to copy the value and only treat the value not the alias? 我假设它是因为@_
的别名,但不应该foreach my $input (@_)
强制sub复制值并且只处理值而不是别名?
I know I can simplify this sub and I used it only as an example. 我知道我可以简化这个子,我只用它作为例子。
Elements of @_
are aliases to the original variables. @_
元素是原始变量的别名。 What you are observing is the difference between: 您所观察到的是以下区别:
sub ltrim {
$_[0] =~ s/^\s+//;
return $_[0];
}
and 和
sub ltrim {
my ($s) = @_;
$s =~ s/^\s+//;
return $s;
}
Compare your code to: 将您的代码与:
#!/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);
}
}
}
Output: 输出:
$ ./zz.pl
name: [ foo ]
sn: [foosu]
Note also that the loop variable in for my $input ( @array )
does not create a new copy for each element of the array. 另请注意for my $input ( @array )
中的循环变量不会为数组的每个元素创建新副本。 See perldoc perlsyn
: 见perldoc perlsyn
:
The
foreach
loop iterates over a normal list value and sets the scalar variableVAR
to be each element of the list in turn.foreach
循环遍历正常列表值,并将标量变量VAR
依次设置为列表的每个元素。 ... ...... ...
the
foreach
loop index variable is an implicit alias for each item in the list that you're looping over.foreach
循环索引变量是您循环的列表中每个项的隐式别名。
In your case, this would mean that, at each iteration $input
is an alias to the corresponding element of @_
which itself is an alias to the variable that was passed in as an argument to the subroutine. 在你的情况下,这意味着,在每次迭代时, $input
是@_
的相应元素的别名,它本身是作为子例程的参数传入的变量的别名。
Making a copy of @_
thus prevents the variables in the calling context from being modified. 因此,复制@_
可以防止修改调用上下文中的变量。 Of course, you could do something like: 当然,你可以这样做:
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);
}
}
}
but I find making a wholesale copy of @_
once to be clearer and more efficient assuming you do not want to be selective. 但我发现,如果你不想选择性的话,那么制作一份@_
的批发副本就会更清晰,更有效率。
I assume it is because of the alias with
@_
, but shouldn't theforeach my $input (@_)
force the sub to copy the value and only treat the value not the alias? 我假设它是因为@_
的别名,但不应该foreach my $input (@_)
强制sub复制值并且只处理值而不是别名?
You're right that @_
contains aliases. 你是对的,@ @_
包含别名。 The part that's missing is that foreach
also aliases the loop variable to the current list element. 缺少的部分是foreach
还将循环变量别名化为当前列表元素。 Quoting perldoc perlsyn
: 引用perldoc perlsyn
:
If any element of LIST is an lvalue, you can modify it by modifying VAR inside the loop. 如果LIST的任何元素是左值,您可以通过修改循环内的VAR来修改它。 Conversely, if any element of LIST is NOT an lvalue, any attempt to modify that element will fail. 相反,如果LIST的任何元素不是左值,则任何修改该元素的尝试都将失败。 In other words, the
foreach
loop index variable is an implicit alias for each item in the list that you're looping over. 换句话说,foreach
循环索引变量是您循环的列表中每个项的隐式别名。
So ultimately $input
is an alias for $_[0]
, which is an alias for $name
, which is why you see the changes appearing in $name
. 所以最终$input
是$_[0]
的别名,这是$name
的别名,这就是为什么你看到$name
出现的更改。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.