変数の値を 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
};
}
ただし、何らかの理由で (いや、変更できませんが) ID が一意ではないため、実際にパスとなるキーが必要な場合が何度かあります。そこで、次のような素晴らしいアイデアを思いつきました。すべてをサブルーチンに組み込み、そのキーとして使用する変数の名前を渡します。次のようになります。
load_hash("path");
sub load_hash {
my $key = shift;
#do stuff, and then in while loop
$hash{${$key}} = #and so on
}
しかし、perldb では、x ${path} は $path の値を出力しますが、x ${$key} は常に undef です。
私がやろうとしていることを行う方法はありますか?
TIA
解決
このような何か?
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;
}