Perl意外结果
假设我有这个Perl脚本Perl意外结果,perl,parameter-passing,Perl,Parameter Passing,假设我有这个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) = @_; $
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]
在调用trim
后打印值时,我希望$name为“[foo]
”,但子对象正在按我的要求设置$name
。为什么这是工作,当它真的不应该
我没有通过引用传递$name,而且trim
sub没有返回任何内容。我希望trim
sub创建$name
值的副本,处理副本,但是原始$name
在主代码中打印时仍会有前导和尾随空格
我假设这是因为别名为@
,但是foreach my$input(@\u)
不应该强制sub复制值,只处理值而不处理别名吗
我知道我可以简化这个潜艇,我只是把它作为一个例子
我假设这是因为别名为@
,但是foreach my$input(@\u)
不应该强制sub复制值,只处理值而不处理别名吗
你说得对,@
包含别名。缺少的部分是,foreach
还将循环变量别名化为当前列表元素。引述:
如果列表中的任何元素是左值,可以通过在循环中修改VAR来修改它。相反,如果列表中的任何元素不是左值,任何修改该元素的尝试都将失败。换句话说,foreach
循环索引变量是列表中要循环的每个项目的隐式别名
因此,归根结底,
$input
是$[0]
的别名,它是$name
的别名,这就是为什么在$name
元素中出现的更改是原始变量的别名。您所观察到的是以下两者之间的差异:
sub ltrim {
$_[0] =~ s/^\s+//;
return $_[0];
}
及
将您的代码与以下代码进行比较:
#!/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
姓名:[foo]
序号:[福苏]
还要注意,中的循环变量对于我的$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);
}
}
}
但是如果你不想有选择性的话,我发现一次完整地复制@
会更清晰、更有效。我认为你在这里回答了错误的问题。OP说“我假设这是因为别名为@
,但是foreach my$input(@
)不应该强制sub复制值,只处理值而不是别名吗?”因此似乎知道@
包含实际参数的别名,但并不是说for
循环的控制变量也是一个别名。@Borodin试图澄清。祝贺您获得了100k!:)@非常感谢你。
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);
}
}
}