2009-08-19 57 views
4

在Perl中,如果一個變量包含另一個變量的名稱,我該如何使用第一個變量訪問另一個變量?如何在Perl中使用符號引用?

例如,讓

$name = "bob"; 
@bob = ("jerk", "perlfan"); 

我應該如何使用$名稱來了解什麼樣的人鮑勃的是什麼? 儘管我不太清楚,但我的模糊記憶告訴我它可能與typeglob有關。

回答

18

幾點:

  • 你是不是在談論類型團,你是在談論符號引用
  • 請勿使用符號引用 - 它們會導致難以追蹤錯誤。
  • 幾乎在任何情況下,符號引用似乎是一個好主意,使用基於散列的數據結構是最好的方法。
  • 考慮在不想改變它們時使用Hash :: Util來鎖定哈希。
  • 符號引用不適用於詞法變量。
  • Typeglobs不適用於詞法變量。
  • 使用詞法變量。
  • 請勿使用符號引用。

查看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。符號引用僅適用於符號表中的值。換句話說,詞法變量不適用於符號引用。

爲防萬一我沒有強調這個,不使用符號引用

+0

準確。你很容易在第二顆子彈之後停下來。我相應地編輯了問題的標題。 – innaM 2009-08-19 07:57:52

+1

對於技術上正確和令人驚訝的全面解釋如何做到這一點以及爲什麼不做。 – 2009-08-19 07:59:22

13

這是非常糟糕的做法。如果你需要這樣做,這意味着你應該重構你的代碼。也許有一個名爲鍵的哈希會更好:

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"; 
+2

+1避免不好的做法比想辦法讓壞的做法發生好得多 – 2009-08-19 10:09:47

+0

這就是符號引用在做什麼:邪惡在於,通過使用符號引用,一個是處理程序的符號表作爲自己的私人散列,當然這不是。所以,**使用散列**。不要使用符號引用。 (我認爲這不能被強調)。 – 2009-08-19 10:56:09

3

你真的不應該這樣做,看到depesz對備選答案,但...

{ 
    no strict 'refs'; 
    print join(q{, }, @$name); 
} 

是的,你可以使用一個字符串標量作爲變量引用,並按名稱查找變量。

您也可以使用typeglobs做到這一點,請參閱符號模塊以獲取簡單的方法。

+0

+1爲技術上正確的答案,並同意你永遠不應該這樣做。 – 2009-08-19 07:57:30

0
no strict 'refs'; 
print "$name is @$name\n"; 
2

通常,當您認爲需要使用符號引用時,通過使用散列(關聯數組)可以更好地服務。

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 

你應該注意到,這是很難的符號引用安全,這就是爲什麼你不應該使用它們。

當然,除非你是一個高級的專家。

相關問題