Почему я получаю «ARRAY (0x145030c)», пытаясь записать Perl-хэш в файл? - PullRequest
0 голосов
/ 23 марта 2010

У меня есть хэш, в котором я храню товары, которые покупает покупатель (%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] равно 0 & rarr; Title, 1 & rarr; price, 2 & rarr; quantity.

Проблема здесь в том, что когда я смотрю на 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 ]

4 голосов
/ 23 марта 2010

Вы хотите перебрать

keys %inventory

а не

%inventory

, который, как вы видите, заставляет вас перебирать пары ключ-значение.

3 голосов
/ 23 марта 2010

Вы используете свой хэш в контексте списка, поэтому все ваши значения добавляются вашими ключами. Я думаю, что вы действительно хотите сделать, это:

foreach $key (keys %inventory) {
    print FILE "...";
}
2 голосов
/ 23 марта 2010

Вот один из способов написания этой подпрограммы:

#!/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 успешно выполнено, прежде чем предположить, что все напечатанные данные действительно сохранены.

  • Вы ДОЛЖНЫ использовать строгие и предупреждения , поскольку на данном этапе вашего обучения вы не знаете Достаточно знать, чего не знаешь.o

2 голосов
/ 23 марта 2010

РЕДАКТИРОВАТЬ: я был неправ о необходимости использовать явную стрелку разыменования; при необходимости это делается в скобках, даже если первые скобки НЕ требуют разыменования. Тем не менее, я оставлю оставшуюся часть ответа в том виде, в каком она была опубликована с тех пор, как он был принят, но просто учтите, что если вы решите не использовать 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";
}

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...