【问题标题】:The correct way to play with data references in Perl在 Perl 中使用数据引用的正确方法
【发布时间】:2014-10-17 22:11:44
【问题描述】:

我有一组数据要处理。

为了简化我的代码,最好通过指向原始数据的引用数组来访问我的一些数据子集。

比解释更好,我写下了这个例子(它还没有工作)。最后,我想更新原始数据而不必更新所有子集。

可以用 Perl 做这样的事情吗?

#!/usr/bin/env perl
use strict;
use warnings;

# A set of data
my $design = {
    box => {
        ne =>  {data => 'north-east'},
        nw =>  {data => 'north-west'},
        n  =>  {data => 'north'},
        s  =>  {data => 'south'},
        e  =>  {data => 'east'},
        w  =>  {data => 'west'},
        se  => {data => 'south-east'},
        sw  => {data => 'south-west'}
    }
};

# Select a design
my $selected = 'box';

# Build some arrays
my $d = $design->{$selected};

my @eastside  = (\$d->{e}, \$d->{ne}, \$d->{se});
my @westside  = (\$d->{w}, \$d->{nw}, \$d->{sw});
my @northside = (\$d->{n}, \$d->{ne}, \$d->{nw});

# Update one data
$d->{ne}->{data} .= " updated!";

# Display
print join '', "Composed of:\n", map("\t".$_->{data}."\n", @eastside);

脚本应该输出:

Composed of:
   east
   north-east updated!
   south-east

【问题讨论】:

    标签: perl hash reference


    【解决方案1】:

    所有的错误是你在像这样的行中引用了已经是哈希引用的值

    my @eastside  = (\$d->{e}, \$d->{ne}, \$d->{se})
    

    您应该简单地省略反斜杠,一切都会正常。

    (顺便说一句,你可能想知道引用\ 运算符是可分配的,所以你可以用

    my @eastside  = \( $d->{e}, $d->{ne}, $d->{se} )
    

    但这样就不再正确了!)

    其他几点

    • 在需要使用多个键提取散列元素列表的情况下,您应该使用 散列切片。在这种情况下,@eastside 只是 @{$d}{qw/ ne e se /}

    • Perl 允许省略右大括号和大括号对之间的间接运算符->,因此$d->{ne}->{data} 可以写成$d->{ne}{data}

    • 您正在打印 join 的结果,元素之间为空。只需列出要打印的项目,您就会得到相同的结果。您还可以将哈希元素插入双引号字符串,因此"\t".$_->{data}."\n""\t$_->{data}\n" 相同

    进行这些更改会导致此工作程序

    use strict;
    use warnings;
    
    # A set of data
    my $design = {
       box => {
          ne => {data => 'north-east'},
          nw => {data => 'north-west'},
          n  => {data => 'north'},
          s  => {data => 'south'},
          e  => {data => 'east'},
          w  => {data => 'west'},
          se => {data => 'south-east'},
          sw => {data => 'south-west'},
       }
    };
    
    # Select a design
    my $selected = 'box';
    
    # Build some arrays
    my $d = $design->{$selected};
    
    my @eastside  = @{$d}{qw/ ne e se /};
    my @westside  = @{$d}{qw/ nw w sw /};
    my @northside = @{$d}{qw/ nw n ne /};
    
    # Update one item
    $d->{ne}{data} .= " updated!";
    
    # Display
    print "Composed of:\n"; 
    print "   $_->{data}\n" for @eastside;
    

    输出

    Composed of:
       north-east updated!
       east
       south-east
    

    【讨论】:

    • 为什么需要@{$d}{qw/ ... /} 而不是@$d{qw/.../}?这里有一些副作用吗? (或者只是为了更好的可读性?)
    • @jm666:这里没有必要,但是使用引用的表达式有时可能不太清楚。如果%hash 是数组的散列,那么要取消引用其中一个值,我必须明确说明我要取消引用的内容并写入@{ $hash{key} }。但这看起来与@$hash{key} 非常相似,它是一个散列的单个元素slice,由标量$hash 引用 - 一个完全不同的变量。因此,我认为最好忽略仅由运算符优先级导致的行为,并指出在这两种情况下要取消引用的内容,并给出@{$hash}{key}
    【解决方案2】:

    您在@eastside 数组中有标量引用,因此为了取消引用标量,请在$_->{data} 前面添加额外的$,或使用${$_}->{data}

    print join '', "Composed of:\n", map("\t".$$_->{data}."\n", @eastside);
    

    输出

    Composed of:
        east
        north-east updated!
        south-east
    

    【讨论】:

      【解决方案3】:

      您可以使用 Data::Dumper 模块检查数据结构。

      还要检查接下来的两个@east2@east3 示例,尤其是@east3 是如何构建的。

      #!/usr/bin/env perl
      use 5.010;
      use warnings;
      use Data::Dumper;
      
      # A set of data
      my $design = {
          box => {
              ne =>  {data => 'north-east'}, nw =>  {data => 'north-west'},
              n  =>  {data => 'north'}, s  =>  {data => 'south'},
              e  =>  {data => 'east'}, w  =>  {data => 'west'},
              se  => {data => 'south-east'}, sw  => {data => 'south-west'}
          }
      };
      my $selected = 'box';
      
      my $d = $design->{$selected};
      
      #your example
      my @east1  = (\$d->{e}, \$d->{ne}, \$d->{se});
      say Dumper \@east1;
      
      my @east2  = ($d->{e}, $d->{ne}, $d->{se});
      say Dumper \@east2;
      
      my @east3 = @$d{qw(e ne se)};
      say Dumper \@east3;
      
      $d->{ne}->{data} .= " updated!";
      
      print join '', "Composed of:\n", map("\t".$$_->{data}."\n", @east1);
      
      print join '', "Composed of:\n", map("\t".$_->{data}."\n", @east2);
      print join '', "Composed of:\n", map("\t".$_->{data}."\n", @east3);
      

      打印:

      $VAR1 = [
                \{
                    'data' => 'east'
                  },
                \{
                    'data' => 'north-east'
                  },
                \{
                    'data' => 'south-east'
                  }
              ];
      
      $VAR1 = [
                {
                  'data' => 'east'
                },
                {
                  'data' => 'north-east'
                },
                {
                  'data' => 'south-east'
                }
              ];
      
      $VAR1 = [
                {
                  'data' => 'east'
                },
                {
                  'data' => 'north-east'
                },
                {
                  'data' => 'south-east'
                }
              ];
      
      Composed of:
          east
          north-east updated!
          south-east
      Composed of:
          east
          north-east updated!
          south-east
      Composed of:
          east
          north-east updated!
          south-east
      

      【讨论】:

        猜你喜欢
        • 2020-09-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-04
        • 2012-07-26
        • 2012-09-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多