2013-06-20 15 views
7

frage ich mich, wie ich in Perl tun kann, was ich tue, häufig in Lisp:Dynamische Variablen in Perl

(defvar *verbose-level* 0) 
(defun my-function (... &key ((:verbose-level *verbose-level*) *verbose-level*) ...) ...) 

bedeutet dies, dass my-function auf dem aktuellen Niveau von Ausführlichkeit ausgeführt wird, aber ich kann es passiert ein andere Ebene, die auch alle ihre Anrufe beeinflussen:

(defun f1 (&key ((:verbose-level *verbose-level*) *verbose-level*)) 
    (format t "~S: ~S=~S~%" 'f1 '*verbose-level* *verbose-level*) 
    (f2 :verbose-level 1) 
    (format t "~S: ~S=~S~%" 'f1 '*verbose-level* *verbose-level*) 
    (f2 :verbose-level (1+ *verbose-level*)) 
    (format t "~S: ~S=~S~%" 'f1 '*verbose-level* *verbose-level*)) 
(defun f2 (&key ((:verbose-level *verbose-level*) *verbose-level*)) 
    (format t "~S: ~S=~S~%" 'f2 '*verbose-level* *verbose-level*)) 
[17]> (f1) 
F1: *VERBOSE-LEVEL*=0 
F2: *VERBOSE-LEVEL*=1 
F1: *VERBOSE-LEVEL*=0 
F2: *VERBOSE-LEVEL*=1 
F1: *VERBOSE-LEVEL*=0 
NIL 
[18]> (f1 :verbose-level 4) 
F1: *VERBOSE-LEVEL*=4 
F2: *VERBOSE-LEVEL*=1 
F1: *VERBOSE-LEVEL*=4 
F2: *VERBOSE-LEVEL*=5 
F1: *VERBOSE-LEVEL*=4 

(beachten Sie, dass die Variablenbindungen beim Beenden gestellt werden - auch abnormal - von Funktionen).

Wie kann ich so etwas in Perl machen? B. in misc.pm, habe ich our $verbose=0;. Wie schreibe ich eine Funktion, die $verbose an einen Wert seines Arguments binden und seinen Wert bei Rückgabe wiederherstellen würde?

Antwort

10

Perls Konzept der globalen Variablen ist ziemlich ähnlich zu speziellen Variablen in CL.

Sie können „Schatten“ der Wert einer globalen Variablen mit local:

our $var = 1; 

func("before"); 

{ 
    # a block creates a new scope 
    local $var = 2; 
    func("inside"); 
} 

func("after"); 

sub func { say "@_: $var" } 

Ausgang:

before: 1 
inside: 2 
after: 1 

Wenn Sie local ein Wert, der neue Wert ist sichtbar in der gesamten Dynamikumfang , dh in allen Funktionen, die aufgerufen werden. Der alte Wert wird wiederhergestellt, sobald der lexikalische Bereich auf irgendeine Weise verlassen wurde (Fehler, Rückgabe usw.). Tail-Aufrufe erweitern den dynamischen Bereich nicht, sondern zählen als Bereichsexit.

Beachten Sie, dass globale Variablen einen vollständig qualifizierten Namen haben. Von einem anderen Paket, würden Sie so etwas wie

local $Other::Package::var = 3; 
Other::Package::func("from a package far, far away"); 

Dies wird im Allgemeinen zur Verfügung zu stellen Konfiguration für Pakete mit einer funktionellen (nicht-OO) Schnittstelle verwendet. Wichtige Beispiele sind Carp und Data::Dumper.

+1

Es ist irgendwie lustig, die Ähnlichkeiten zwischen Perl und CL zu sehen. Beginnend mit dem Kompilierungsmodell (warum * sollte * Code nicht während des Parsens ausgeführt werden?) Über spezielle vs. lexikalische vars bis zu separaten Namespaces (CL: Variablen, Funktionen, Labels, Streams, ...; Perl: Skalare, Arrays, Hashes, Subs, IO, ...).Oh, und CLOS/Moose sind offensichtlich verwandt – amon

3

Wenn ich Sie richtig verstehe, müssen Sie eine globale Variable innerhalb einer Funktion lokal überschreiben.

package my_package; 
our $verbose = 0; 

sub function { 
    my ($arg1, $arg2) = @_; # getting function arguments. 
    local $verbose = $arg1; 
} 

Es wird alten Zustand von $verbose bei der Rückkehr wiederherstellen.

+0

Danke. Was passiert, wenn 'Funktion' ohne Argumente aufgerufen wird? D.h., "$ arg1" ist nicht gebunden. Muss ich auf 'local $ verbose = defined $ arg1 zurückgreifen? $ arg1: $ verbose' oder gibt es einen schöneren Ansatz? – sds

+0

Sie können 'local $ verbose = $ arg1 schreiben, wenn $ arg1;' definiert ist. –

+0

Das ergibt keinen Sinn. Wenn '$ arg1' nicht definiert ist, ist' $ verbose' nicht definiert. Was Sie tun können, ist 'local $ verbose = shift; $ verbose = "default" falls nicht definiert $ verbose; '(Oder benutze den definierten oder Zuweisungsoperator:' $ verbose // = "default" '). – TLP