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

StackOverflow https://stackoverflow.com/questions/1726363

Вопрос

Извините за все эти глупые вопросы, я увлекся программированием на 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;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top