Как я могу использовать значение переменной в качестве имени переменной 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;
}