为什么我会尝试将“Perl哈希”写入文件“ARRAY(0x145030c)”?

时间:2010-03-23 19:52:59

标签: perl hash

我有一个哈希,我在其中存储客户购买的产品(%orders)。它使用产品代码作为键,并引用一个数组,其他信息作为值。

在程序结束时,我必须将库存重写为更新版本(即减去购买商品的数量)

这就是我重写库存的方式:

sub rewriteInventory{
    open(FILE,'>inv.txt');
    foreach $key(%inventory){
        print FILE "$key\|$inventory{$key}[0]\|$inventory{$key}[1]\|$inventory{$key}[2]\n"
    }
    close(FILE);
}

其中$inventory{$key}[x]0Title1price2quantity

这里的问题是,当我看到inv.txt之后,我会看到这样的事情:

CD-911|Lady Gaga - The Fame|15.99|21
ARRAY(0x145030c)|||
BOOK-1453|The Da Vinci Code - Dan Brown|14.75|12
ARRAY(0x145bee4)|||

这些ARRAY(0x145030c)|||条目来自哪里?或者更重要的是,我该如何摆脱它们呢?

4 个答案:

答案 0 :(得分:4)

你想迭代

keys %inventory

而不是

%inventory

,如您所见,使您迭代键值对。

答案 1 :(得分:3)

您在列表上下文中使用了哈希,因此您可以使用密钥获取所有值。我想你真正想做的是:

foreach $key (keys %inventory) {
    print FILE "...";
}

答案 2 :(得分:2)

编辑:我不得不使用明确的解除引用箭头;这是在必要时在括号之间推断的,即使第一个括号不需要取消引用。也就是说,我将保留答案的其余部分,因为它已被接受,但只是注意,如果您选择不使用join,则无需实际使用$inventory{$key}->[0],但实际上可以使用最初发布的$inventory{$key}[0]

请注意,第一个(哈希)括号不表示取消引用,但第二个(数组)括号表示。输出中的错误数组引用不仅来自循环键,还来自循环的值。

原始回答:

除了使用keys之外,您还需要取消引用数组引用(这就是为什么您看到每个值输出为带有地址的ARRAY ---您正在打印引用,当你打印时,不是取消引用数组的值),所以你的循环就像:

foreach my $key (sort keys %inventory) {
    print FILE "$key\|$inventory{$key}->[0]\|$inventory{$key}->[1]\|$inventory{$key}->[2]\n";
}

我可能会更加惯用地重写它:

foreach my $key (sort keys %inventory) {
    print FILE (join '|', $key, @{$inventory{$key}}) . "\n";
}

希望有所帮助!

答案 3 :(得分:2)

这是编写该例程的一种方法:

#!/usr/bin/perl

use strict; use warnings;

my %inventory;

while ( my $line = <DATA> ) {
    chomp $line;
    my ($key, @values) = split qr{\|}, $line;
    last unless @values;
    $inventory{$key} = \@values;
}

write_inventory(\%inventory, 'test.txt');

sub write_inventory {
    my ($inventory, $output_file) = @_;

    open my $output, '>', $output_file
        or die "Cannot open '$output_file': $!";

    for my $item ( keys %$inventory ) {
        unless ( 'ARRAY' eq ref $inventory{$item} ) {
            warn "Invalid item '$item' in inventory\n";
            next;
        }

        print $output join('|', $item, @{ $inventory{$item} }), "\n";
    }

    close $output
        or die "Cannot close '$output': $!";
}
__DATA__
CD-911|Lady Gaga - The Fame|15.99|21
BOOK-1453|The Da Vinci Code - Dan Brown|14.75|12

规则是:

  • 不要使用全局变量:将对%inventory的引用传递给write_inventory,而不是让它在全局%inventory上运行。

  • 不要使用全局变量:使用范围限制为FILE的词法文件句柄,而不是使用具有包范围的裸字文件句柄write_inventory

  • 检查文件操作错误:确保open成功,然后继续前进并尝试写入。假设您打印的所有数据实际上已保存,请确保close成功。

  • 必须 使用strictwarnings因为,在您学习过程的这一点上,您还不够了解知道你不知道的事情。