2010-06-14 7 views
6

Manchmal brauche ich eine nützliche Dienstprogrammfunktion, wie List::Util::max in der Mitte eines großen Programms, das viele Sachen macht. Also, wenn ich an der Spitze von meinem ProgrammLexikalische Import von nützlichen Funktionen in einem großen Skript

use List::Util 'max'; 

tun, ich bin mit diesem Symbol stecken, meinen ganzen Namensraum verschmutzen, obwohl ich es nur in einem Unterprogramm benötigen.

use List::Util(); 

# a whole bunch of stuff later... 
sub blah { 
    List::Util->import('max'); 
    $blah = max @foobar; 
    ... 
} 

Es gibt zwei Probleme mit diesem, aber:

ein anderes Muster zu versuchen, anstatt So denke, ich habe. Zum einen wird es nicht automatisch am Ende des Blocks unimport (drat.) Müsste ich alles mit einem unimport rückgängig machen.

Das andere Problem ist, dass anscheinend Prototypen nicht richtig angewendet werden, so muss ich max(@foobar) anstelle der hübscheren Klammer-Version sagen.

Gibt es eine einfache Möglichkeit, Symbole für einen Block vorübergehend zu importieren, was automatisch dazu führen würde, dass sie am Ende des Blocks weggehen, und auch Prototypen richtig handhaben?

Antwort

1

Sie können einen Symboltabelleneintrag lokalisieren:

use List::Util(); 

@y = qw(1 3 5 -9 4); 

sub max { # return maximum *absolute value* of list 
    my $max = abs(shift); 
    $max<abs($_) && ($max=$abs($_)) for @_; 
    return $max; 
} 

sub max2 { 
    local *max = *List::Util::max; 
    return max(@_); 
} 

print "My max:   ", max(@y), "\n"; # ==> 9 
print "List::Util::max ", max2(@y), "\n"; # ==> 5 
+3

Dies wird subtile Fehler einführen, wenn 'max' einen Prototyp hat, da der Effekt davon zur Kompilierzeit eingebrannt wird. In 'max2' wird der Prototyp von' main :: max' verwendet, nicht der von 'List :: Util :: max'. Hilfsweise sollten Sie eine Warnung über die fehlende Übereinstimmung des Prototyps bei der Zuweisung erhalten. –

+0

@Eric Strom - Guter Punkt, das würde saugen. Verwenden Sie einen 'lokalen' Unterprogrammnamen mit Vorsicht. – mob

4

Genau dies zu tun, es ist viel besser und sauberer:

package Foo; 
use strict; use warnings; 
use List::Util 'max'; 
use namespace::autoclean; 

# your method definitions here... 

namespace::autoclean wird „unimport“ das Symbol nach dem Kompilierung Zyklus des Pakets erfolgt. Der Aufruf in Ihrer Methode wird weiterhin funktionieren, aber Sie haben keine Namespace-Verschmutzung (das *Foo::max-Symbol wird entfernt) und das Aufrufen von $obj->max() wird fehlschlagen.

Alternativ können Sie einen Blick auf Lexical::Import werfen (ich weiß nichts darüber; ein irc Birdie erwähnte es).

+0

Während 'Namespace :: autoclean' ist spiffy, es ist nicht das Hauptproblem nicht lösen, das ist, dass' max' in das gesamte Paket ist immer noch da, anstatt beschränkt sich auf einen einzigen Block, der ist was ich wirklich versuche zu erreichen. Ich möchte, dass meine Dienstprogrammfunktionen sich wie lexikalische Variablen verhalten. – friedo

+0

@friedo: Warum ist es ein Problem, dass 'max' für das gesamte Paket verfügbar ist? Wenn das Problem die Namespace-Verschmutzung ist, kümmert sich dieses Modul darum. – Ether

+0

Vielleicht möchte ich ein * anderes * 'max' woanders im Paket haben. – friedo

1

perlfunc implizieren, dass no MODULE sollte das tun, was Sie wollen:

sub blah { 
    use List::Util qw(max); 
    say max @foobar; 
    no List::Util; 
} 

aber das funktioniert nicht - zumindest nicht für List: : Nützlich. Ich glaube, dass es eine unimport Methode definieren müsste. Selbst dann, ich bin mir nicht sicher, ob Sie eine bare max in Ihrem Modul verschiedene Definitionen aufrufen können.

+0

Würden die Zeilen 'use' und' no' nicht zu einem anderen (früheren) Zeitpunkt ausgeführt als der Rest der Unterdefinition? – Ether

+0

Sowohl 'use' als auch' no' treten zur Kompilierzeit auf; Sie würden ausgeführt werden, während "blah" zusammengestellt wurde. –

2

Wenn Sie max nur in einer Subroutine verwenden, würde ich sie nicht in den Namespace importieren. Meine Lösung ist zu

use List::Util; 
sub blah { 
    print List::Util::max(@list); 
} 
+0

Damit werden noch Prototypen geehrt, so dass Sie die Klammern weglassen können: print List :: Util :: max @list; – dwarring

Verwandte Themen