我从来没有真正学过Perl,但我正在通过我的工作做一个课程(我能说“只是为了好玩吗?”)。 我理解基础知识没有任何重大问题,但我现在正在学习参考文献和速记。我对数组的速记和访问引用值有疑问,请考虑下面的两个脚本:
@Codes =
(
["A1W",
["A2Q","A2Z"]],
["B2R","BB3"]
);
$CodeRef = \@Codes;
#full notation
print @{@{@{$CodeRef}[0]}[1]}[1], "\n";
#shorthand notation
print $CodeRef->[0]->[1]->[1], "\n";
my $BookPageArray;
{
$AnotherArray = [24, 18, 36];
$Reference = \$AnotherArray;
$BookPageArray = \$AnotherArray;
$AnotherArray = [53, 256, 42]; count drops to 0
}
undef $Reference;
print ${$BookPageArray}->[0]."\n";
我的问题是为什么在第二个例子中,最终print语句中的$BookPageArray
引用需要在它周围使用大括号,而在第一个示例中,$ CodeRef引用不是?
如果我在第二个例子中取出大括号和前面的$
符号,它告诉我该引用没有数组......
是否与第二个示例使用匿名数据这一事实有关?
答案 0 :(得分:10)
哇,这是糟糕的代码!我知道这不是你的错。
引用通常是数组或散列,但$BookPageArray
是引用到引用到数组引用。这是炫耀还是假设教你?
大括号就像数学表达式的括号一样。它们可能有助于澄清或混淆。
my $answer = 3 + 4 x 5 + 6; # Example 1
my $answer = 3 + ( 4 x 5 ) + 6; # Example 2
my $answer = ( 3 + 4 ) X ( 5 + 6 ); # Example 3
实施例1和实施例2是相同的。括号是否澄清?你可以说他们这样做。在例3中,括号是必要的。
my $answer = 1 + 3 + 4 + 9 + 10;
my $answer = ( ( ( ( 1 + 3 ) + 4 ) + 9 ) + 10 );
同样,这些都是相同的。问题是括号是否澄清了正在发生的事情(他们没有)或使其更难理解(他们这样做)。
这些也是等同的:
print $foo . "\n";
print ${foo} . "\n";
花括号在某些情况下可以提供帮助:
print "The file name is ${foo}_bar.txt\n";
在这里,你需要花括号才能让Perl知道变量是$foo
而不是$foo_bar
。这些是等价的:
print "The file name is ${foo_bar}.txt\n";
print "The file name is $foo_bar.txt\n";
所以,在你的陈述中你有:
${$BookPageArray}->[0]."\n";
有些人喜欢这样,因为它有助于强调${BookPageArray}
是标量参考,并帮助您看到此引用被取消引用:
${$BookPageArray}->[0]."\n"; # I see that this is a scalar reference being dereferenced
$$BookPageArray->[0]."\n"; # Didn't notice the `$$`, so missed the dereferencing.
${${$BookPageArray}}[0]."\n"; # Yes, this is the same thing!
当您取消引用数组和哈希时,箭头->
语法可以帮助澄清事情。
my $value = $foo->{BAR}; # I can see that `$foo` is a reference to an array!
my $value = ${${foo}}{BAR}; # Ow! This hurts my brain
my $value = $$foo{BAR}; # Easier on the brain, but I'll miss that `$foo` is a ref.
这些都是等价的,但第一个是最容易理解的。不幸的是,解除引用标量没有->
等价物。幸运的是,它并没有经常这样做。
大多数情况下,只需完成引用即可创建复杂的数据结构:
my $person = {}; # This will be a hash reference (not necessary)...
$person->{NAME} = "Bob";
$person->{ADDR} = "123 Testing Ave.";
$person->{CITY} = "New York";
$person->{STATE} = "CA"; #Got you!
$person->{PHONE} = []; # Array Reference (not necessary)
$person->{PHONE}->[0] = {}; # Hash reference (not necessary)
$person->{PHONE}->[0]->{TYPE} = "cell";
$person->{PHONE}->[0]->{NUMBER} = "555-1234";
您可以在此结构中看到,我有一个人,其中包含姓名,地址和多个电话号码。
我不必声明某些内容是数组引用或哈希引用,但它有时可以澄清您要存储的内容。 my $person = {};
不是必需的。我本可以做my $person
,但它有助于澄清它是你正在使用的参考。声明电话号码的数组参考可能会增加烟雾而不是光线,不应该这样做。将$person->{PHONE}->[0]
声明为哈希引用实际上只会减少正在发生的事情。
我建议使用内置Perl reference tutorial。它直截了当,易于理解。我还建议你在Modern Perl上获得一本好书,因为Perl的编码风格和语法自Perl 3.x以来已经发生了很多变化,很多Perl书籍似乎都依赖于它。
在您熟悉参考文献后,您应该阅读Object Oriented Perl tutorial。面向对象的Perl基本上是使用引用创建复杂的数据结构,但是这样做可以很容易地跟踪复杂的结构。
跟踪这样的事情有点复杂:$person->{PHONE}->[0]->{NUMBER} = "555-1234";
答案 1 :(得分:5)
你可以删除curlies:
$$BookPageArray->[0]."\n";
您需要两个$
,因为BookPageArray是对数组引用的引用。所以第一个'$'获取对数组的引用,箭头取消引用并索引数组。
答案 2 :(得分:5)
请注意
print @{@{@{$CodeRef}[0]}[1]}[1], "\n"; # Array slices
应该是
print ${${${$CodeRef}[0]}[1]}[1], "\n"; # Array lookups by index
你可以在这里使用数组表示法。
print $CodeRef->[0]->[1]->[1], "\n";
简化为
print $CodeRef->[0][1][1], "\n";
注意this table中的相似之处。
答案 3 :(得分:1)
我的问题是为什么在第二个例子中,最终print语句中的$ BookPageArray引用需要在它周围使用大括号,而在第一个示例中,$ CodeRef引用不是?
在第二个示例中,$BookPageArray
具有标量引用,$CodeRef
具有数组引用。每个都应该被正确解除引用(@$$BookPageArray
vs @$CodeRef
),否则你会得到例外。
要清楚地看到标量和数组引用之间的区别,请检查
perl -MData::Dumper -e '
@arr = 10..14;
$aref = \@arr;
$sref = \$aref;
print Dumper $aref;
print Dumper $sref;
'
输出
$VAR1 = [
10,
11,
12,
13,
14
];
$VAR1 = \[
10,
11,
12,
13,
14
];