2010-11-25 8 views
1

Je souhaite définir une variable avec un nom choisi dans un autre package. Comment puis-je le faire facilement?Définir une variable dans un autre package

Quelque chose comme:

$variable_name = 'x'; 
$package::$variable_name = '0'; 
# now $package::x should be == '0' 
+0

Il est mauvais de bricoler avec d'autres variables de paquets. Perl le permet, mais vous faites violence à la conception de l'autre paquet. Bien sûr, il y a une mise en garde: si la variable est exportée par le paquet (non recommandé, mais certainement faisable), alors vous pouvez avoir l'autorisation de l'utiliser et vous n'avez alors rien d'autre à faire que de lui assigner. –

+0

@Jonathan: Je dois mettre à jour un ancien code. Avant, il fallait 'require magic_config_file.pl;' (à partir du chemin absolu) quand il avait besoin de sa configuration. Je le passe à un module qui peut lire les fichiers de configuration locaux appropriés, mais pour la rétrocompatibilité, je dois définir '% main :: SOME_DB = (hôte => 'blah', utilisateur => 'blah' ....' – viraptor

+1

@Jonathan Leffler: une plus grande mise en garde: si elle est documentée que vous pouvez (par exemple Data :: Dumper, Text :: Wrap, etc.) – ysth

Répondre

1

Étant donné que $variable_name a été validé, vous pouvez faire:

eval "\$package::$variable_name = '0'"; 
+0

Vous n'avez vraiment pas besoin de recourir à un 'eval STRING' juste pour le faire. – tchrist

2

Vous pouvez le faire, mais vous devez désactiver rétrécissements comme ceci:

package Test; 

    package main; 

    use strict; 

    my $var_name = 'test'; 
    my $package = 'Test'; 

    no strict 'refs'; 
    ${"${package}::$var_name"} = 1; 

print $Test::test; 

donc je ne recommanderais pas. Mieux vaut utiliser un hachage.

1
use 5.010; 
use strict; 
use warnings; 

{ 
    no warnings 'once'; 
    $A::B::C::D = 5; # a test subject 
} 

my $pkg = 'A::B::C'; 
my $var = 'D'; 

# tearing down the walls (no warranty for you): 
    say eval '$'.$pkg."::$var"; # 5 

# tearing down the walls but at least feeling bad about it: 
    say ${eval '\$'.$pkg."::$var" or die [email protected]}; # 5 

# entering your house with a key (but still carrying a bomb): 
    say ${eval "package $pkg; *$var" or die [email protected]}; # 5 

# using `Symbol`:  
    use Symbol 'qualify_to_ref'; 
    say $${ qualify_to_ref $pkg.'::'.$var }; # 5 

# letting us know you plan mild shenanigans 
# of all of the methods here, this one is best 
{ 
    no strict 'refs'; 
    say ${$pkg.'::'.$var}; # 5 
} 

et si le sens pour vous suivre, un rapport sur:

# with a recursive function: 
    sub lookup { 
     @_ == 2 or unshift @_, \%::; 
     my ($head, $tail) = $_[1] =~ /^([^:]+:*)(.*)$/; 
     length $tail 
      ? lookup($_[0]{$head}, $tail) 
      : $_[0]{$head} 
    } 
    say ${ lookup $pkg.'::'.$var }; # 5 

# as a reduction of the symbol table: 
    use List::Util 'reduce'; 
    our ($a, $b); 

    say ${+ reduce {$$a{$b}} \%::, split /(?<=::)/ => $pkg.'::'.$var }; # 5 

Et bien sûr, vous pouvez attribuer à aucune de ces méthodes au lieu de say les ing.

+0

Pourquoi «réduire» me fait-il toujours mal au cerveau? :) – tchrist