2009-08-19 7 views
4

In Perl, wenn eine Variable den Namen für eine andere Variable enthält, wie verwende ich die erste Variable, um die andere Variable zu besuchen?Wie verwende ich symbolische Referenzen in Perl?

Zum Beispiel lassen

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

wie soll ich $ name verwenden, um zu wissen zu bekommen, welche Art von Person bob ist? Obwohl ich mir nicht ganz sicher bin, sagt mir meine vage Erinnerung, dass es sich auf typeglob beziehen könnte.

Antwort

18

Mehrere Punkte:

  • Sie sind nicht über Typeglobs reden, Sie sprechen über symbolische Referenzen.
  • Verwenden Sie keine symbolischen Referenzen - sie führen dazu, dass Fehler nur schwer aufgespürt werden können.
  • In fast allen Fällen, in denen symbolische Referenzen eine gute Idee zu sein scheinen, ist die Verwendung einer Datenstruktur basierend auf einem Hash der beste Ansatz.
  • Verwenden Sie Hash :: Util, um Ihre Hashes zu sperren, wenn Sie sie nicht ändern möchten.
  • Symbolische Referenzen funktionieren nicht mit lexikalischen Variablen.
  • Typeglobs funktionieren nicht mit lexikalischen Variablen.
  • Verwenden Sie lexikalische Variablen.
  • Verwenden Sie keine symbolischen Referenzen.

Siehe perlreftut für mehr auf Referenzen (symbolische und andere). Hilfe zur Verwendung von Datenstrukturen finden Sie unter perldsc. Weitere Informationen zu Typeglobs finden Sie unter perlmod. Weitere Informationen zu lexikalischen Variablen finden Sie unter perlsub.

Hier ist ein Beispiel von gesperrten Hashes mit Zugriff auf die Daten über den Inhalt einer Variablen zu steuern:

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; 
} 

Alle Warnungen beiseite, die Syntax symbolische Referenzen zu verwenden, sollten Sie es verwenden müssen (aber Sie nicht) ist:

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

Beachten Sie, dass das Array @bob mit our deklariert wird. Symbolische Referenzen funktionieren nur mit Werten in der Symboltabelle. Mit anderen Worten, lexikalische Variablen funktionieren nicht mit symbolischen Referenzen.

Für den Fall, ich habe das nicht genug betont, verwenden Sie keine symbolischen Referenzen.

+0

Genau. Sie hätten leicht nach der zweiten Kugel anhalten können. Ich habe den Titel der Frage entsprechend bearbeitet. – innaM

+1

+1 für eine technisch korrekte und erstaunlich umfassende Erklärung, wie man es macht und warum nicht. –

13

Dies ist sehr schlechte Praxis. Wenn Sie jemals tun müssen, bedeutet dies, dass Sie Ihren Code umgestalten sollten. Vielleicht ein Hash mit dem Namen Schlüssel wäre besser:

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 um die schlechte Praxis zu vermeiden ist viel besser als einen Weg zu finden, um die schlechte Praxis passieren zu lassen –

+0

Das ist, was symbolische Referenzen sowieso tun: Das Böse ist in der Tatsache, dass man mit symbolischen Referenzen die Programme behandelt Symboltabellen als eigenen privaten Hash, der es natürlich nicht ist. Also, ** benutze einen Hash **. Verwenden Sie keine symbolischen Referenzen. (Ich denke nicht, dass dies genug betont werden kann). –

3

Sie sollten wirklich nicht, dies zu tun haben, depesz Antwort für die Alternative zu sehen, aber ...

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

Ja, können Sie ein String-Skalar als Variablenreferenz, und es sucht die Variable nach Namen.

Sie können dies auch mit typeglobs tun, sehen Sie das Symbol-Modul für eine einfache Möglichkeit.

+0

+1 für die technisch korrekte Antwort und für die Zustimmung, dass Sie dies nie tun sollten. –

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

Wenn Sie normalerweise denken, dass Sie symbolische Referenzen verwenden müssen, werden Sie besser mit einem Hash (assoziative Array) bedient.

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"; 
    } 
    } 
} 

Ergebnisse in:

 
jerk perlfan 
mary had a little lamb 
susan not found 

Wenn Sie denken, Sie wirklich symbolische Referenzen verwenden müssen, ist dies ein sicherer Weg, das zu tun.

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" 
    } 
    } 
} 

Welche zurück:

 
jerk perlfan 
# mary is not an array, it's a scalar 
mary had a little lamb 
susan not found 

Sie sollten beachten, dass es schwieriger zu symbolischen Referenzen ist sicher, weshalb man sie nicht verwenden sollten.

Es sei denn, Sie sind ein Experte, etwas fortgeschrittenes zu tun.

Verwandte Themen