2013-03-12 64 views
3

你好,我正在学习Perl,我会在这里发表几个假设。所以请随时评论和纠正我,如果我在某个地方错了。Perl - 匿名hashmaps和数组 - 几个问题

  1. 创建哈希完成(几另一个方法中)由:

    %numbers = qw(one 1 two 2); 
    
  2. 创建阵列完成由以下几点:

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

    %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,摩登家庭,辛普森)我应该使用哪种建设创建%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 
    } 
    
+2

您应该只对每个问题提出一个问题。 – TLP 2013-03-12 15:00:19

回答

1

我称他们为 “文字散”, “文字阵”,但对每一个他自己。

你应该知道在Perl中 - 除了在tie s-- [...]\@x的情况下几乎是相同的事情。那{...}\%h也是。他们都“构建”对数组和散列的引用。

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

$HOH{flinstones} = {%flinstones} 

创建一个哈希返回地址和扩展%flintstones到一个列表,每个列表环境。因此,它将存储在%HOH中的单独散列中存储散列,该散列是%flintstones的精确副本。您对%flintstones的更改不会影响此副本是正确的。

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

下面是我的经验,一些经验与SC:

  • 设置$Data::Dumper::Maxdepth一些正整数,如果你将倾Win32::OLE对象,相同的OLE对象的每个引用可以看起来像遍历时不同的Perl对象。

  • 从不转储$_本身。出于某种原因,SC中的代码可以改变它。所以总是这样做:

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

现在,终于,如果你不与%HOH倾倒%flintstones,你就没有办法知道 - 通过一个简单的变量转储 - 引用是否相同或不。但是,请记住,您可以设置$Data::Dumper::Maxdepth,以便您不会得到完整的转储。因此,您可以通过部分转储它们并使用直接的通用Perl引用的引用来测试两个引用是否相同。

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

看到自己是什么的情况下,是要帮助你学习的Perl比要求的#2问题木筏快。

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 
1

{ LIST }建设获取值的列表,并从它们中构建一个匿名哈希(就像您将同一列表分配给名为%hash = (LIST)的哈希)并返回对该哈希的引用。

Perl中的“匿名哈希”没有什么特别之处:它们与其他任何平常的哈希都是一样的。唯一让他们“匿名”的是他们目前没有名字,所以你只能用引用来引用他们。

被绑定到一个变量名称并不是散列的内部属性,它可能是:命名散列很有可能变成匿名(例如,如果它的名称超出了范围),或者甚至是匿名散列通过symbol table manipulation获得一个名字,就像这样:

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

*hash = $hashref后,全局变量%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到不同的(现在匿名)数组,而不是多个引用指向同一个数组。