4

我从来没有真正深入地学习过 Perl,但我正在通过我的工作学习一门课程(我可以说“只是为了好玩”吗?)。我理解基础知识没有任何大问题,但现在正在学习参考和速记。我对数组的简写和访问引用值有疑问,请考虑以下两个脚本:

  1.  

    @Codes =
            (
             ["A1W",
              ["A2Q","A2Z"]],
             ["B2R","BB3"]
            );
    $CodeRef = \@Codes;
    
    #full notation
    print @{@{@{$CodeRef}[0]}[1]}[1], "\n";
    
    #shorthand notation
    print $CodeRef->[0]->[1]->[1], "\n";
    
  2.  

    my $BookPageArray;
    {
            $AnotherArray = [24, 18, 36]; 
            $Reference = \$AnotherArray; 
            $BookPageArray = \$AnotherArray; 
            $AnotherArray = [53, 256, 42];  count drops to 0
    }
    undef $Reference;
    print ${$BookPageArray}->[0]."\n";
    

我的问题是为什么在第二个示例中$BookPageArray最终打印语句中的引用需要大括号括起来,而在第一个示例中 $CodeRef 引用不需要?

如果我在第二个示例中取出大括号和前面的$符号,它会告诉我该引用处没有数组...

是否与第二个示例使用匿名数据有关?

4

4 回答 4

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 知道变量 is$foo和 not $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 参考教程。它直截了当且易于理解。我还建议你买一本关于现代 Perl的好书,因为 Perl 的编码风格和语法自 Perl 3.x 以来发生了变化,许多 Perl 书籍似乎仍然基于这些。

在熟悉了引用之后,您应该阅读面向对象的 Perl 教程。面向对象的 Perl 基本上是使用引用创建复杂的数据结构,但这样做的方式是便于跟踪复杂的结构。

跟踪这样的事情有点复杂:$person->{PHONE}->[0]->{NUMBER} = "555-1234";

于 2013-11-06T14:48:26.573 回答
5

您可以删除卷曲:

$$BookPageArray->[0]."\n";

您需要两个$s,因为 BookPageArray 是对数组引用的引用。所以第一个 '$' 得到对数组的引用,箭头取消对它的引用并索引数组。

于 2013-11-06T13:48:17.650 回答
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";

请注意此表中的相似之处。

于 2013-11-06T14:31:27.047 回答
1

我的问题是,为什么在第二个示例中,最终打印语句中的 $BookPageArray 引用需要用大括号括起来,而在第一个示例中,$CodeRef 引用不需要?

在第二个示例$BookPageArray中,有标量引用,并且$CodeRef有数组引用。每个都应该被正确地取消引用(@$$BookPageArrayvs @$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
          ];
于 2013-11-06T13:55:44.927 回答