Come posso utilizzare il valore di una variabile come un nome di variabile Perl? [duplicare]
-
19-09-2019 - |
Domanda
Questa domanda ha già una risposta qui:
Mi dispiace per tutte queste domande stupide, sono stato spinto in programmazione Perl e sto trovando davvero difficile pensare come un programmatore Perl.
domanda stupida per oggi: Carico un file delimitato pipe in un hash utilizzando il campo ID come la chiave, in questo modo
#open file
my %hash;
while (<MY_FILE>) {
chomp;
my ($id, $path, $date) = split /\|/;
$hash{$id} = {
"path" => $path,
"date" => $date
};
}
C'è un paio di volte, però, quando ho effettivamente bisogno la chiave per essere il percorso perché, per qualsiasi motivo (e no, non può essere modificato) l'id non è unico, così ho avuto la brillante idea che ho potuto mettere tutto in una subroutine e passare il nome della variabile da utilizzare come chiave ad esso, un po 'in questo modo:
load_hash("path");
sub load_hash {
my $key = shift;
#do stuff, and then in while loop
$hash{${$key}} = #and so on
}
ma in perldb x $ {$ key} è sempre undef, anche se x $ {path} stampa il valore di $ percorso.
C'è un modo di fare quello che sto cercando di?
TIA
Soluzione
Una cosa come questa?
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
}
}
Altri suggerimenti
Si sta cercando di usare "riferimenti simbolici". Se hai un problema e si pensa "hey, io risolvere questo con riferimenti simbolici" Ora avete due problemi.
In primo luogo, essi funzionano solo su variabili globali. Hai dichiarato $path
come lessicale (visibili solo nel blocco che è stato dichiarato) e quindi load_path Non si può vedere. No, non fanno $path
globale.
In secondo luogo, arbitri simbolici creano spaghetti code. Globali sono già abbastanza grave. Essi sono accessibili ovunque e in qualsiasi momento da qualsiasi cosa. Con un riferimento simbolico a una globale non si può anche vedere quale mondiale si accede. Questo rende impossibile per tenere traccia di ciò che potrebbe cambiare quello. Questo è il motivo per cui strict
li si spegne. Accendere strict
e lasciarlo acceso finché non si sa quando si dovrebbe spegnerlo.
Non sono del tutto sicuro di quello che stai cercando di realizzare, ma sembra questo va bene.
my %hash;
while (<MY_FILE>) {
chomp;
my ($id, $path, $date) = split /\|/;
$hash{$path} = {
"path" => $path,
"date" => $date
};
}
Ma avrei probabilmente spostare il parsing della linea in una funzione e lasciare l'incarico di hash per il ciclo principale. Analisi della riga è un chiaro pezzo di logica e totalmente separato dal assegnare la riga al file hash. Un buon segno è che %hash
non deve essere globale.
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;
}