Как я могу использовать значение переменной в качестве имени переменной Perl?[дубликат]
-
19-09-2019 - |
Вопрос
На этот вопрос уже есть ответ здесь:
Извините за все эти глупые вопросы, я увлекся программированием на 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.
Есть ли какой-то способ сделать то, что я пытаюсь?
ТИА
Решение
Что-то вроде этого?
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;
}