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) = @_; $

假设我有这个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]
在调用
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);
       }
   }
}