3

您好我正在学习 perl,我将在这里发布几个假设。因此,如果我在某处错了,请随时评论和纠正我。

  1. 通过以下方式创建哈希(在其他几种方式中):

    %numbers = qw(one 1 two 2);
    
  2. 创建数组通过以下方式完成:

    @array = qw(one two);
    
  3. 以上结构代表“非匿名”类型。非匿名类型和匿名类型之间的主要区别在于命名类型有一个我可以参考的名称。如果我想创建匿名类型,我需要更改数组中方()括号[]{}散列中大括号的括号。换句话说,散列的散列是对其他散列的引用的散列。因此我需要{}在嵌套 hash 而不是经典 hash中使用()

    %HoH = (
        flintstones => {
            husband   => "fred",
            pal       => "barney",
        },
        jetsons => {
            husband   => "george",
            wife      => "jane",
            "his boy" => "elroy",  # quotes needed on key.
        },
        simpsons => {
            husband   => "homer",
            wife      => "marge",
            kid       => "bart",
        },
    );
    
  4. 同样的情况也适用于多维数组。多维数组是一个包含对另一个数组的引用的数组,因此需要使用 [] 代替 ()。

    @array_of_arrays =  ( [ "one", "two", "three" ],
                          [  4,   5,  6,  7  ],
                          [ "alpha", "beta" ]
                        );
    
  5. 如果我有包含每个家庭成员(flinstones、jetsons、simpsons)的“非匿名”哈希,我应该使用哪个结构来创建%HOH

    $HOH{flinstones} = {%flinstones};
    

    或者

    $HOH{flinstones} = \%flinstones;
    

    我假设这\%flinstones只是简单地将引用分配给$HOH{flinstones},这意味着我所做的任何事情%flinstones都会影响 ,$HOH{flinstones}因为它只包含对它的引用。另一方面{%flinstones},类似于将“非匿名”哈希重新转换为“匿名”哈希。这具有%flinstones以后可以修改甚至删除的效果,并且不会影响,$HOH{flinstones}因为存在对匿名哈希的引用。

  6. 循环中的变量会发生什么?当my $variable;在循环内发出时,它会覆盖旧的或创建新的,或者它是同一个变量,或者这里会发生什么?

    for($i=0;$i<4;$i++){
      my $variable=$i;
      print $variable
    }
    
4

3 回答 3

3

至于问题 5,我假设是问题 1,你可以同时使用。尽管您应该意识到第一种方法:

$HOH{flinstones} = {%flinstones}

只是简单地制作散列的浅表副本,将%flinstones其扩展为其键和值的列表。然而

$HOH{flinstones} = \%flinstones

将散列作为引用传递,以便两个散列指向内存中的相同位置。

至于问题 6,词法范围的变量会发生什么?让我们来看看perldoc -f my

A "my" declares the listed variables to be local (lexically) to
the enclosing block, file, or "eval".

for 循环是一个块,这意味着my在 for 循环内声明的任何变量都是该循环的本地变量,并且该循环的每次迭代都是本地的。这意味着如果您执行以下操作:

for my $number (0 .. 3) {
    print "Number is $_. Last number was $last\n";
    my $last = $_;                       # WRONG!
}   # $last goes out of scope here!

它会给你很多Use of uninitialized value警告。您需要扩大范围:

my $last = "N/A";  # default value
for my $number (0 .. 3) {
    print "Number is $_. Last number was $last\n";
    $last = $_;
}

现在,我不知道这是否是您故意的,但您可以将这两个问题合二为一:

my %HOH;
{ # begin a block to reduce scope of variables
    my %flinstones = (
        husband   => "fred",
        pal       => "barney",
    );
    $HOH{flinstones} = \%flinstones;
} 
... # %flinstones hash is now out of scope, stored only in %HOH
于 2013-03-12T15:26:59.443 回答
1

{ LIST }构造采用一个值列表,从中构建一个匿名散列(就像您将相同的列表分配给具有 的命名散列一样%hash = (LIST))并返回对该散列的引用。

Perl 中的“匿名散列”没有什么特别之处:它们和其他散列一样都是普通的散列。使它们“匿名”的唯一原因是它们(当前)没有名称,因此您只能使用引用来引用它们。

绑定到变量名也不是散列的固有属性:命名散列很可能变得匿名(例如,如果它的名称超出范围),甚至匿名散列通过符号表操作,像这样:

my $hashref = {foo => 'bar'};
our %hash;             # required by "use strict"
*hash = $hashref;
print "$hash{foo}\n";  # prints "bar"

在 line 之后*hash = $hashref,全局变量%hash成为 reference 指向的 hash 的新名称$hashref,无论它之前是否已经有名称。这种机制甚至允许同一个散列有多个名称:事实上,任何允许您将散列(或任何其他类型的变量)从其自己的名称空间导出到您的名称空间的 Perl 模块本质上就是在幕后做到这一点的。

当然,以上所有内容也同样适用于数组(实际上也适用于标量)。


至于你的最后一个问题,my实际上每次执行时都会创建一个新的词法范围变量,而不是每次都重用同一个变量。这实际上对您的示例代码没有任何影响,但产生影响的一种情况是,如果您在变量超出范围之前保存了对变量的引用。例如,以下是将制表符分隔的数据解析为数组的一种相当常见的方法:

my @table;
while (my $line = <>) {
    chomp $line;
    my @row = split /\t/, $line;
    # maybe do some manipulation or checks on @row here...
    push @table, \@row;
}

如果您对此进行测试,您会发现此代码确实@table为每一行填充了对不同(现在是匿名)数组的引用,而不是许多指向同一个数组的引用。

于 2013-03-12T17:52:10.637 回答
1

我称它们为“文字哈希”、“文字数组”,但对每个人来说都是他自己的。

你应该知道,在 Perl 中——除了ties——[...]\@x几乎是一回事。这{...}也是\%h。它们都“构造”对数组和散列的引用。

在问题 5 中,两者都会做你想做的事。但是一个人会更有效地做到这一点。您的第二个示例将对已定义哈希的引用存储为另一个哈希中的值。第一个例子,

$HOH{flinstones} = {%flinstones}

根据列表上下文创建一个散列以返回地址并扩展 %flintstones为一个列表。因此,它将一个哈希值%flintstones存储在一个单独的哈希值的精确副本中,该哈希值存储在%HOH. 您是正确的,更改%flintstones不会影响此副本。

这里给你一点建议。安装,Smart::Comments(SC),创建一些测试脚本,然后通过 STDERR 转储变量内部。你会惊讶于你可以学到更多的东西,看到一切的内部,你愿意看到。

以下是我对 SC 的一些经验教训:

  • $Data::Dumper::Maxdepth如果要转储对象,请设置为某个正整数值Win32::OLE,因为同一 OLE 对象的每个引用在遍历时可能看起来像不同的 Perl 对象。

  • 永远不要自己倾倒$_。由于某种原因,SC 中的代码可以更改它。所以总是做这样的事情:

    my $a = $_;
    ### $_ : $a
    
  • IO 句柄不会转储,所以不要尝试。使用默认字符串化。

现在,最后,如果您不使用 转储%flintstones%HOH您将无法通过简单的变量转储知道引用是否相同。但是,请记住,您可以设置$Data::Dumper::Maxdepth为不会获得完整的转储。因此,您可以通过部分转储它们并使用直接的通用 Perl 引用字符串化来测试两个引用是否相同。

### %flintstones : '' . \%flintstones 
local $Data::Dumper::Maxdepth = 1;
### %HOH

亲眼看看是什么情况,这将比在 Stackoverflow 上问一大堆问题更快地帮助你学习 Perl。

于 2013-03-12T15:20:25.737 回答