在Perl中,如果一個變量包含另一個變量的名稱,我該如何使用第一個變量訪問另一個變量?如何在Perl中使用符號引用?
例如,讓
$name = "bob";
@bob = ("jerk", "perlfan");
我應該如何使用$名稱來了解什麼樣的人鮑勃的是什麼? 儘管我不太清楚,但我的模糊記憶告訴我它可能與typeglob有關。
在Perl中,如果一個變量包含另一個變量的名稱,我該如何使用第一個變量訪問另一個變量?如何在Perl中使用符號引用?
例如,讓
$name = "bob";
@bob = ("jerk", "perlfan");
我應該如何使用$名稱來了解什麼樣的人鮑勃的是什麼? 儘管我不太清楚,但我的模糊記憶告訴我它可能與typeglob有關。
幾點:
查看perlreftut更多關於參考(符號和其他)。 請參閱perldsc以獲取使用數據結構的幫助。 有關typeglobs的更多信息,請參閱perlmod。 有關詞彙變量的更多信息,請參閱perlsub。
下面是使用鎖定哈希來控制基於變量的內容訪問數據的例子:
use strict;
use warnings;
use Hash::Util qw(lock_hash unlock_hash);
my %data;
lock_hash(%data);
#Altering %data is a fatal exception.
unlock_hash(%data);
%data = (
'bob' => [ 'jerk', 'genius' ],
);
lock_hash(%data);
for my $name (qw/ bob margaret /) {
my $info = $data{$name}; # Fatal error when accessing data for margaret.
print "$name is a\n";
print map "\t$_\n", @$info;
}
所有的警告放在一邊,用符號引用的語法如果你需要使用它(但你不會)是:
use strict;
use warnings;
my $name = 'bob';
our @bob = qw/jerk genius/;
my $qualities;
{ no strict 'refs';
print "$name: ", @$name, "\n";
$qualities = \@$name;
}
print "$name is a @$qualities\n";
注意,陣列@bob
聲明與our
。符號引用僅適用於符號表中的值。換句話說,詞法變量不適用於符號引用。
爲防萬一我沒有強調這個,不使用符號引用。
這是非常糟糕的做法。如果你需要這樣做,這意味着你應該重構你的代碼。也許有一個名爲鍵的哈希會更好:
my %data = (
'bob' => [ 'jerk', 'perlfan' ],
);
my $name = 'bob';
print $data{ $name }->[0], "\n";
print $data{ $name }->[1], "\n";
my $stringified = join ' and ', @{ $data{ $name } };
print $stringified, "\n";
+1避免不好的做法比想辦法讓壞的做法發生好得多 – 2009-08-19 10:09:47
這就是符號引用在做什麼:邪惡在於,通過使用符號引用,一個是處理程序的符號表作爲自己的私人散列,當然這不是。所以,**使用散列**。不要使用符號引用。 (我認爲這不能被強調)。 – 2009-08-19 10:56:09
你真的不應該這樣做,看到depesz對備選答案,但...
{
no strict 'refs';
print join(q{, }, @$name);
}
是的,你可以使用一個字符串標量作爲變量引用,並按名稱查找變量。
您也可以使用typeglobs做到這一點,請參閱符號模塊以獲取簡單的方法。
+1爲技術上正確的答案,並同意你永遠不應該這樣做。 – 2009-08-19 07:57:30
no strict 'refs';
print "$name is @$name\n";
初學者往往認爲他們想有一個變量包含變量的名稱。 ...
簡答:不。長答案:閱讀FAQ條目(您的計算機上也有這個條目)。較長的回答:閱讀MJD的Why it's stupid to "use a variable as a variable name"(Part 2,Part 3)。
通常,當您認爲需要使用符號引用時,通過使用散列(關聯數組)可以更好地服務。
use strict;
use warnings;
my %user = (
'bob' => [qw' jerk perlfan '],
'mary' => 'had a little lamb',
);
{
for my $name (qw'bob mary susan'){
if(exists $user{$name}){
if(ref($user{$name}) eq 'ARRAY'){
print join(' ', @{$user{$name}}), "\n";
}else{
print $name, ' ', $user{$name}, "\n";
}
}else{
print "$name not found\n";
}
}
}
結果:
jerk perlfan mary had a little lamb susan not found
如果你覺得你真的需要使用符號引用,這是做一個更安全的方式。
use strict;
use warnings;
# can't use my
our @bob = ("jerk", "perlfan");
our $mary = 'had a little lamb';
{
for my $name (qw'bob mary susan'){
if(exists $::{$name}){
my $ref = $::{$name};
if(*{$ref}{ARRAY}){
print join(' ',@$ref), "\n";
}elsif(*{$ref}{SCALAR}){
print "# $name is not an array, it's a scalar\n";
print $name, ' ', $$ref, "\n";
}
}else{
print "$name not found\n"
}
}
}
將返回:
jerk perlfan # mary is not an array, it's a scalar mary had a little lamb susan not found
你應該注意到,這是很難的符號引用安全,這就是爲什麼你不應該使用它們。
當然,除非你是一個高級的專家。
符號引用是值得避免的,但如果您確實想要使用它們,則它們具有與常規引用相同的使用語法:請參見http://perlmonks.org/?node=References+quick+reference。
準確。你很容易在第二顆子彈之後停下來。我相應地編輯了問題的標題。 – innaM 2009-08-19 07:57:52
對於技術上正確和令人驚訝的全面解釋如何做到這一點以及爲什麼不做。 – 2009-08-19 07:59:22