Как я могу использовать значение переменной в качестве имени переменной Perl?

Извините за все эти глупые вопросы, я был увлечен программированием на Perl, и мне очень трудно думать, как программист на Perl.

Глупый вопрос на сегодня: я загружаю файл с разделителем канала в хеш, используя поле id в качестве ключа, вот так

#open file

my %hash;
while (<MY_FILE>) {
    chomp;

    my ($id, $path, $date) = split /\|/;

    $hash{$id} = {
        "path" => $path,
        "date" => $date
    };
}

Однако в некоторых случаях мне нужно, чтобы ключом был путь, потому что по какой-либо причине (и нет, его нельзя изменить) идентификатор не является уникальным, поэтому у меня возникла блестящая идея, что я мог бы поставить все это в подпрограмму и передайте имя переменной для использования в качестве ключа к ней, примерно так:

load_hash("path");

sub load_hash {
    my $key = shift;

    #do stuff, and then in while loop
    $hash{${$key}} = #and so on
}

но в perldb x ${$key} всегда undef, хотя x ${path} печатает значение в $path.

Есть ли способ сделать то, что я пытаюсь сделать?

ТИА

2 ответа

Решение

Что-то вроде этого?

use Carp 'confess';

sub load_hash {
    my $key = shift;

    # ...

    while (...) {
        # ...
        my %line;  # important that this is *inside* the loop
        @line{qw (id path date)} = split /\|/;
        confess "BUG: unknown key '$key'"  unless exists $line{$key};  # error checking
        $hash{$line{$key}} = \%line;
        delete $line{$key};  # assuming you don't want the key value duplicated
    }
}

Вы пытаетесь использовать "символические ссылки". Если у вас есть проблема, и вы думаете "эй, я решу ее с помощью символических ссылок", у вас теперь есть две проблемы.

Во-первых, они работают только на глобалах. Вы объявили $path как лексический (видимый только в блоке, в котором он был объявлен) и, следовательно, load_path не может его увидеть. Нет не делают $path Глобальный.

Во-вторых, символические ссылки создают код спагетти. Глобалы достаточно плохие. К ним можно получить доступ где угодно и когда угодно. Имея символическую ссылку на глобал, вы даже не видите, к КАКОЙ глобализации обращаются. Это делает невозможным отслеживание того, что может изменить что. Вот почему strict выключает их Включи strict и оставьте его включенным, пока не узнаете, когда следует его выключить.

Я не совсем уверен, чего вы пытаетесь достичь, но, похоже, это нормально.

my %hash;
while (<MY_FILE>) {
    chomp;

    my ($id, $path, $date) = split /\|/;

    $hash{$path} = {
        "path" => $path,
        "date" => $date
    };
}

Но я бы, вероятно, переместил разбор строки в функцию и оставил бы присвоение хеша главному циклу. Разбор строки представляет собой четкую часть логики и может быть полностью отделен от назначения строки хешу файла. Хороший знак в том, что %hash не должен быть глобальным.

my %hash;
while (<MY_FILE>) {
    my $line = parse_line($_);

    my $id = $line->{path};
    $hash{$id} = $line;
}


my @fields = qw(id path date);
sub parse_line {
    my $line = shift;
    chomp $line;

    my %data;
    # This is assigning to a hash slice.  Look it up, its handy.
    @data{@fields} = split m{\|}, $line;

    return \%data;
}
Другие вопросы по тегам