【问题标题】:Is it possible to increment a scalar reference in Perl?是否可以在 Perl 中增加标量引用?
【发布时间】:2015-11-28 06:33:51
【问题描述】:

假设我有一个数字,$x = 0;,我想用子程序递增它,但子程序不会返回它的值:

sub increment {
    my ($var) = @_;

    my @list = (
        'a',
        'b',
        'c',

        ...

        'x',
        'y',
        'z'
    );

    return $list[$var++];
}

while ($x < 10) {
    print increment($x);
}

按原样,这将永远打印aaaaaaaaaa 而不是abcdefghij。如果我将increment($x) 替换为increment(\$x),它会将标量地址转换为十进制数并改为递增。在上面的场景中,它最终会抛出一个错误,因为 25423331 或任何不是有效的数组元素。

如果 $x 是散列或数组中的元素,我可以将父元素作为引用传递给修改原始元素:

$x = {'val' => 0};
while ($x->{'val'} < 10) {
    print increment($x);
}

sub increment {
    ...
    return $list[$var->{$val}++];
}

如何修改标量引用的原始值?

【问题讨论】:

  • 会指出-您实际上不需要做所有这些。你可以改为my $letter = 'a'; print $letter++ for ( 1..10 );
  • 即使我提供的答案符合您的要求,但我通常建议您避免做这样的事情。让循环索引“远距离”递增有点令人迷惑。
  • @Sobrique 我不敢相信这行得通,但这种行为甚至是documented。谢谢你今天教我一些新东西。
  • @MattJacob range operator 的工作方式相同,允许您执行 say for 'a' .. 'zz'; 之类的操作
  • @ThisSuitIsBlackNot 我知道那个,但我不认为增加一个字符串会起作用,更不用说产生一些令人满意的输出了。

标签: perl pass-by-reference


【解决方案1】:

您可以传递对变量的引用进行修改。

sub increment {
    my ($ref) = @_;
    ++$$ref;
}

my $i = 0;
say $i;  # prints 0
increment(\$i);
say $i;  # prints 1

您还可以利用 Perl passes by reference

sub increment {
    ++$_[0];
}

my $i = 0;
say $i;  # prints 0
increment($i);
say $i;  # prints 1

但是这样隐藏增量是一个非常糟糕的主意。要么遍历一个列表,

for my $x ('a'..'z') {
   ...
}

或者写一个迭代器。

sub make_iter {
   my @list = @_;
   return sub {
      return @list ? shift(@list) : ();
   };
}

my $iter = make_iter('a'..'z');
while (my ($x) = $iter->()) {
   ...
}

【讨论】:

  • @DaveSherohman:在任何具有传递引用的语言中,如果将传递引用参数分配给另一个常规局部变量,则该变量是原始变量的独立副本。跨度>
  • 是的,我的立场是正确的。我现在正好在 YAPC::EU,所以我找到了一个 Perl 5 核心开发人员,并询问了 @_ 的别名和 pass-by-reference 之间的区别。他的回答是“哦,这是一个传递引用”。由于我错了,并且此评论讨论将来可能对任何人都没有帮助,因此我将删除我之前的 cmets。
【解决方案2】:

您需要在子例程中取消引用$var,如下所示:

my $x = 0;

say $x;  # prints 0
foo(\$x);
say $x;  # prints 1

sub foo {
    my $y = shift;
    $$y++;
}

【讨论】:

    猜你喜欢
    • 2013-08-29
    • 1970-01-01
    • 1970-01-01
    • 2015-06-21
    • 2018-03-01
    • 1970-01-01
    • 2011-09-15
    • 2013-11-11
    • 1970-01-01
    相关资源
    最近更新 更多