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

Perl-关于解引用的正确语法的两个问题,perl,syntax,dereference,Perl,Syntax,Dereference,作为一名新手,我正在尝试使用亚特兰大perl mongers提供的材料探索perl数据结构,可在此处找到 下面是我编写的示例代码,01.pl与02.pl相同,但01.pl包含另外两个pragma:使用strict;使用警告 #!/usr/bin/perl my %name = (name=>"Linus", forename=>"Torvalds"); my @system = qw(Linux FreeBSD Solaris NetBSD); sub passStructure

作为一名新手,我正在尝试使用亚特兰大perl mongers提供的材料探索perl数据结构,可在此处找到

下面是我编写的示例代码,
01.pl
02.pl
相同,但
01.pl
包含另外两个pragma:
使用strict;使用警告

#!/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);
上述文件中有几点我误解了:

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

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

但第二个不会,为什么

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

[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

我相信您应该以如下方式访问数组:@{$aref}[0]或$aref->[0]


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

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

另一方面,
@{$aref}->[0]
是一个错误,它发生在工作中,但已被弃用,可能不会继续

你可能想读书

包变量
%href
只需提及这样一个散列而不使用有效的
使用严格的“vars”
即可创建,例如将
->
保留在
$href->{'SomeKey'}
之外。这并不意味着创建了特定的密钥


更新:查看Perl最佳实践参考(这本书比作者预期的更容易被采用,实际思考更少),它特别推荐
->
表单,以避免遗漏sigil的可能性,从而导致第45页提到的问题。

$arg->[0]
表单在
$$arg[0]
表单上的作用是,第一种类型更清楚地了解发生了什么…
$arg
是一个ARRAYREF,您正在访问它引用的数组的第0个元素

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

当然,只有一种解释是正确的,但我们都有这样的日子(或夜晚),我们在看代码,我们不太记得顺序运算符和其他语法设备是如何工作的。此外,如果有其他级别的去引用,混乱会加剧

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


至于散列的自动创建…将创建的只是散列(以便Perl解释器检查键是否存在),而不是键本身(当然……您不想创建正在检查的密钥……但是,如果存储桶不存在,您可能需要创建保存该密钥的存储桶。该过程称为Autovification,您可以了解更多信息。

Perl具有正常的数据类型和对数据类型的引用。了解dif非常重要它们之间的差异,无论是在意义上,还是在句法上

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]
语法访问hashref或arrayrefs可能被认为是不好的原因是:(1)双符号看起来像标量ref访问,令人困惑;(2)此语法隐藏了使用引用的事实。取消引用箭头
->
的意图是明确的。我介绍了使用
&
符号不好的原因

@{$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};
输出:
在ref用法时创建

实际上,arrayref已到位,因为在某些情况下可以使用
unde
值作为引用。然后,此arrayref将填充哈希中的插槽

如果没有
使用严格的'refs'
,变量(而不是该变量中的插槽)就会出现,因为全局变量只是表示名称空间的哈希中的条目。
$foo{bar}
$main::foo{bar}
相同

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};