【问题标题】:Perl - Two questions regarding proper syntax for dereferencingPerl - 关于解引用的正确语法的两个问题
【发布时间】:2012-12-27 20:44:58
【问题描述】:

作为一个新手,我正在尝试使用来自 atlanta perl mongers 的材料来探索 perl 数据结构,可在此处获得 Perl Data Structures

这是我编写的示例代码,01.pl02.pl 相同,但 01.pl 包含另外两个 pragma:use strict; use warnings;

#!/usr/bin/perl

my %name = (name=>"Linus", forename=>"Torvalds");
my @system = qw(Linux FreeBSD Solaris NetBSD);

sub passStructure{
  my ($arg1,$arg2)=@_;

  if (ref($arg1) eq "HASH"){
    &printHash($arg1);
  }
  elsif (ref($arg1) eq "ARRAY"){
    &printArray($arg1);
  }

  if (ref($arg2) eq "HASH"){
    &printHash($arg2);
  }
  elsif (ref($arg2) eq "ARRAY"){
    &printArray($arg2);
  }
}

sub printArray{
  my $aref = $_[0];

  print "@{$aref}\n";
  print "@{$aref}->[0]\n";
  print "$$aref[0]\n";          
  print "$aref->[0]\n";
}

sub printHash{
  my $href = $_[0];

  print "%{$href}\n";
  print "%{$href}->{'name'}\n";
  print "$$href{'name'}\n";
  print "$href->{'name'}\n";
}

&passStructure(\@system,\%name);

上面文件中提到的几点我误解了:

第一 第 44 页提到这两种语法结构:"$$href{'name'}""$$aref[0]" 永远不应该用于访问值。为什么 ?似乎在我的代码中它们工作正常(见下文),而且 perl 抱怨不推荐使用 @{$aref}->[0],那么哪个是正确的?

第二 第 45 页提到,如果不使用 "use strict" 并在应使用 "$href->{'SomeKey'}" 时使用 "$href{'SomeKey'}",则会隐式创建 %href。所以如果我理解得很好,下面的两个脚本都应该打印“Exists”

    [pista@HP-PC temp]$ perl -ale 'my %ref=(SomeKey=>'SomeVal'); print $ref{'SomeKey'}; print "Exists\n" if exists $ref{'SomeKey'};'
    SomeVal
    Exists

    [pista@HP-PC temp]$ perl -ale '                              print $ref{'SomeKey'}; print "Exists\n" if exists $ref{'SomeKey'};'

但是第二个不会,为什么?

两个开头提到的脚本的输出:

[pista@HP-PC temp]$ perl 01.pl 
Using an array as a reference is deprecated at 01.pl line 32.
Linux FreeBSD Solaris NetBSD
Linux
Linux
Linux
%{HASH(0x1c33ec0)}
%{HASH(0x1c33ec0)}->{'name'}
Linus
Linus
[pista@HP-PC temp]$ perl 02.pl 
Using an array as a reference is deprecated at 02.pl line 32.
Linux FreeBSD Solaris NetBSD
Linux
Linux
Linux
%{HASH(0x774e60)}
%{HASH(0x774e60)}->{'name'}
Linus
Linus

【问题讨论】:

    标签: perl syntax dereference


    【解决方案1】:

    很多人认为$$aref[0] 丑,$aref->[0] 不丑。其他人不同意;前一种形式没有问题。

    另一方面,@{$aref}->[0] 是一个错误,碰巧有效,但已被弃用,可能不会继续。

    您可能想阅读http://perlmonks.org/?node=References+quick+reference

    一个包变量%href 是通过提及这样一个没有use strict "vars" 有效的散列来创建的,例如通过将-> 排除在$href->{'SomeKey'} 之外。这并不意味着创建了特定的密钥。

    更新:查看 Perl Best Practices 参考资料(这本书激发了更多的盲目采用和比作者预期的更少的实际想法),它特别推荐 -> 表格以避免留下印记的可能性,导致第45页提到的问题。

    【讨论】:

      【解决方案2】:

      Perl 有普通的数据类型,以及对数据类型的引用。了解它们之间的区别很重要,无论是在含义上还是在语法上。

      Type   |Normal Access | Reference Access | Debatable Reference Access
      =======+==============+==================+===========================
      Scalar | $scalar      | $$scalar_ref     |
      Array  | $array[0]    | $arrayref->[0]   | $$arrayref[0]
      Hash   | $hash{key}   | $hashref->{key}  | $$hashref{key}
      Code   | code()       | $coderef->()     | &$coderef()
      

      使用$$foo[0] 语法访问hashrefs 或arrayrefs 被认为是不好的原因是(1)双印记看起来像标量引用访问,并且(2)这种语法隐藏了使用引用的事实。 dereferencing 箭头-> 的意图很明确。我介绍了在this answer 中使用& 印记不好的原因。

      @{$aref}->[0] 是非常错误的,因为您要取消引用对数组的引用(根据定义,它本身不能是引用),然后用箭头取消引用该数组的第一个元素。请参阅上表了解正确的语法。

      将哈希值插入字符串很少有意义。哈希的字符串化表示已填充和可用存储桶的数量,因此可以告诉您有关负载的信息。这在大多数情况下没有用。此外,不将 % 字符视为字符串中的特殊字符允许您使用 printf...

      关于 Perl 数据结构的另一个有趣的事情是知道何时创建了散列或数组中的新条目。通常,访问一个值不会在该哈希或数组中创建一个槽,除非您使用该值作为引用。

      my %foo;
      $foo{bar}; # access, nothing happens
      say "created at access" if exists $foo{bar};
      $foo{bar}[0]; # usage as arrayref
      say "created at ref usage" if exists $foo{bar};
      

      输出:created at ref usage

      实际上,arrayref 就位,因为在某些情况下您可以使用undef 值作为引用。然后这个 arrayref 填充散列中的槽。

      没有use strict 'refs',变量(但不是该变量中的一个槽)就会出现,因为全局变量只是代表命名空间的散列中的条目。 $foo{bar} 等同于$main::foo{bar} 等同于$main::{foo}{bar}

      【讨论】:

        【解决方案3】:

        $arg->[0] 表单相对于$$arg[0] 表单的主要优势在于,第一种类型更清楚地了解正在发生的事情...$arg 是一个 ARRAYREF,您正在访问第 0 个它所引用的数组的元素。

        初读时,第二种形式可以解释为${$arg}[0](取消引用ARRAYREF)或${$arg[0]}(取消引用@arg 的第一个元素。

        当然,只有一种解释是正确的,但我们都有那些日子(或夜晚)在查看代码,我们不太记得顺序运算符和其他句法设备的工作原理。此外,混淆会如果有额外的解除引用级别,则复合。

        防御性程序员往往会在努力使他们的意图明确时犯错,我认为$arg->[0] 是该代码意图的更明确表示。

        至于哈希的自动创建……它只是将被创建的哈希(以便 Perl 解释器检查密钥是否存在)。未创建密钥本身(自然...您不想创建要检查的密钥...但是如果存储桶不存在,您可能需要创建将保存该密钥的存储桶. 这个过程被称为自动生存,你可以阅读更多关于它的信息here

        【讨论】:

          【解决方案4】:

          我相信您应该以 @{$aref}[0] 或 $aref->[0] 的形式访问数组。

          print 语句不会实例化对象。隐式创建的意思是您不需要在分配给它之前预定义变量。由于print 没有赋值,所以没有创建变量。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-11-26
            • 2011-05-30
            • 2011-05-10
            • 2011-10-11
            • 2014-08-01
            相关资源
            最近更新 更多