Perl - 关于解除引用的正确语法的两个问题

时间:2013-01-13 22:51:29

标签: perl syntax dereference

作为一个新手,我正在尝试使用atlanta perl mongers的这种材料来探索perl数据结构,在这里可用Perl Data Structures

以下是我编写的示例代码,01.pl02.pl相同,但01.pl包含其他两个编译指示: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]作为弃用,那么哪一个是正确的?

第二 如果不使用"use strict"并且在使用"$href{'SomeKey'}"时使用"$href->{'SomeKey'}",那么%href会被隐含地创建。因此,如果我理解得很好,以下脚本都应该打印“存在”

    [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

4 个答案:

答案 0 :(得分:5)

许多人认为$$aref[0]丑陋而$aref->[0]并不丑陋。其他人不同意;前一种形式没有错。

另一方面,

@{$aref}->[0]是一个错误,它恰好起作用但被弃用,可能不会继续。

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

简单地通过提及没有%href的哈希来创建包变量use strict "vars",例如将->保留在$href->{'SomeKey'}之外。这并不意味着创建了特定的密钥。

更新:查看Perl最佳实践参考书(这本书激发了更多的盲目采用,减少了实际的思想而不是作者的意图),它专门推荐->表格以避免遗漏sigil,导致p45上提到的问题。

答案 1 :(得分:3)

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)双重sigil看起来像标量引用访问一样令人困惑,并且(2)这种语法隐藏了引用的事实用过的。 de ref erencing arrow ->的意图很明确。我在this answer中说明了使用& sigil的原因很糟糕。

@{$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}相同。

答案 2 :(得分:1)

$arg->[0]形式相对于$$arg[0]形式的主要优势在于,第一种类型的内容更清晰...... $arg是ARRAYREF和你正在访问它引用的数组的第0个元素。

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

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

防御性程序员倾向于努力使他们的意图明确,我认为$arg->[0]更明确地表达了该代码的意图。

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

答案 3 :(得分:0)

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

print语句不会实例化对象。隐式创建的含义是在分配变量之前不需要预先定义变量。由于print未分配,因此未创建变量。