【问题标题】:foreach my $var (@list) -- $var is a reference?foreach my $var (@list) -- $var 是参考吗?
【发布时间】:2009-06-18 15:15:40
【问题描述】:

所以,我从来不知道这一点,我想澄清一下。我知道你是否这样做

foreach (@list){

如果您在该循环中更改 $_,它将影响实际数据。但是,我不知道如果你这样做了

foreach my $var1 (@list){

如果您在循环中更改了 $var1,它会更改实际数据。 :-/ 那么,有没有一种方法可以循环 @list 但将变量保留为只读副本,或者如果更改不会更改 @list 中的值的副本?

【问题讨论】:

    标签: perl foreach perlsyn


    【解决方案1】:

    $var 依次为每个项目设置别名。

    http://perldoc.perl.org/perlsyn.html#Foreach-Loops

    如果 LIST 的任何元素是左值,您可以通过修改循环内的 VAR 来修改它。 相反,如果 LIST 的任何元素不是左值,则任何修改该元素的尝试 将失败。换句话说,foreach 循环索引变量是每个变量的隐式别名 您正在循环的列表中的项目。

    【讨论】:

      【解决方案2】:

      最简单的方法就是复制它:

      foreach my $var1 (@list) {
          my $var1_scratch = $var1;
      

      foreach my $var1 ( map $_, @list ) {
      

      但如果 $var1 是一个引用,那么 $var1_scratch 将是对同一事物的引用。 为了真正安全,您必须使用 Storable::dclone 之类的东西来进行深层复制:

      foreach my $var1 ( @{ Storable::dclone( \@list ) } ) {
      }
      

      (未经测试)。然后您应该能够安全地更改 $var1。但如果它可能会很昂贵 @list 是一个大数据结构。

      【讨论】:

      • 小心,$var1 不是引用,而是别名。看看区别:我的 $var2=\$list[0];打印 "$var2\n";显示标量(0x8171880)
      • @wazoox:他的意思是如果 $var1 包含引用,例如如果@list 包含一堆 HASH 引用。即使你打破了别名,你仍然有另一个引用同一事物的副本。
      【解决方案3】:

      它是别名,而不是引用。如果您想创建自己的别名(在 for 之外),您可以使用 Data::Alias

      【讨论】:

      • 嗯... +0。这是 +1 用于别名/参考说明,-1 用于提供与 OP 要求相反的指示。 (创建别名而不是破坏别名。)
      • @Michael Carman ysth 已经给出了正确的答案,我只是指出可以创建自己的别名。
      【解决方案4】:

      这些循环之间的唯一区别:

      foreach (@array) { ... }
      foreach my $var (@array) { ... }
      

      是循环变量。别名是foreach 的函数,而不是隐式变量$_。请注意,这是一个 alias(同一事物的另一个名称),而不是 reference(一个事物的指针)。

      在简单(和常见)的情况下,您可以通过制作副本来打破别名:

      foreach my $var (@array) {
          my $copy = $var;
          # do something that changes $copy
      }
      

      这适用于普通的标量值。对于引用(或对象),您需要使用 StorableClone 进行深层复制,这可能会很昂贵。绑定变量也有问题,perlsyn 建议完全避免这种情况。

      【讨论】:

      • 或 Clone::More 或 Clone::Fast
      • 或者使用 for my $var (() = @array) 在 foreach 中复制一份
      【解决方案5】:

      我不知道如何在 foreach 语句本身中强制变量按值而不是按引用。不过,您可以复制 $_ 的值。

      #!/usr/perl/bin
      use warnings;
      use strict;
      
      use Data::Dumper;
      
      my @data = (1, 2, 3, 4);
      
      print "Before:\n", Dumper(\@data), "\n\n\n";
      
      foreach (@data) {
          my $v = $_;
          $v++;
      }
      
      print "After:\n", Dumper(\@data), "\n\n\n";
      
      __END__
      

      【讨论】:

      • 你在哪里说my $v = shift;你的意思是my $v = $_;
      • @Dave Hinton 纠正了错误。 @Sukotto 尝试在您最初编写的循环体中打印 $v 以查看您的错误。
      • 是的,我的意思是my $v = $_; :-(
      【解决方案6】:

      在 for 语句中复制@list:

      foreach my $var1 (() = @list) {
        # modify $var without modifying @list here
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-21
        • 2015-10-18
        • 2013-06-22
        • 1970-01-01
        • 2016-07-20
        • 1970-01-01
        • 1970-01-01
        • 2015-02-05
        相关资源
        最近更新 更多