2010-02-16 3 views
7

En Perl, est-il possible de créer une variable globale basée sur une chaîne?Comment puis-je créer un nom de variable Perl basé sur une chaîne?

Par ex, si j'avais une fonction comme:

sub create_glob_var { 
    my ($glob_var_str) = @_; 
    # something like this (but not a hash access). 
    our ${$glob_var_str}; 
}; 

et je l'ai appelé comme:

create_glob_var("bar"); 

Comment pourrais-je modifier create_glob_var réellement créer une variable globale appelée $bar?

Mon projet utilise perl 5.8.5.

EDIT

Ce qui suit ne fonctionne pas:

use strict; 
BEGIN { 
    sub create_glob_var { 
    my ($glob_var_str) = @_; 
    no strict 'refs'; 
    $$glob_var_str = undef; # or whatever you want to set it to 
    } 

    create_glob_var("bah"); 
}; 

$bah = "blah"; 

Produit:

Variable "$bah" is not imported at /nfs/pdx/home/rbroger1/tmp2.pl line 12. 
Global symbol "$bah" requires explicit package name at /nfs/pdx/home/rbroger1/tmp2.pl line 12. 
Execution of /nfs/pdx/home/rbroger1/tmp2.pl aborted due to compilation errors.

NOTE je me rends compte que l'utilisation des variables globales provoque ozone depletion and male pattern baldness. J'essaie de nettoyer un code hérité qui est déjà complètement infecté par l'utilisation de variables globales. Un refactor à la fois ...

+0

Le sous-programme crée la variable globale, mais vous devez toujours y accéder d'une manière acceptable à strict, probablement l'un de 1) $ Mon :: Package :: bah = "blah", 2) utiliser vars qw ($ bah) $ bah = "blah", ou 3) notre $ bah = "blah". – Sean

+4

Ne faites pas ce genre de choses. voir http://stackoverflow.com/questions/1549685/how-can-i-use-a-variable-as-a-variable-name-in-perl –

+0

D'accord. Utilisez un hash global pour stocker des données (si vous devez utiliser des globals du tout), plutôt que de créer de nouveaux scalaires! – Ether

Répondre

5

Si yo Vous essayez de nettoyer l'ancien code, vous pouvez écrire un module qui exporte la (les) variable (s) requise (s). Chaque fois que vous ressentez le besoin d'invoquer create_glob_var, ajoutez plutôt une variable à ce paquet et mettez-la dans la liste d'importation.

Cela vous aidera à garder une trace de ce qui se passe et comment les variables sont utilisées.

package MyVars; 

use strict; use warnings; 

use Exporter 'import'; 

our($x, %y, @z); 

our @EXPORT_OK = qw($x %y @z); 

Le script:

#!/usr/bin/perl 

use strict;use warnings; 

use MyVars qw($x %y @z); 

$x = 'test'; 
%y = (a => 1, b => 2); 
@z = qw(a b c); 

use Data::Dumper; 
print Dumper \($x, %y, @z); 

Sortie:

$VAR1 = \'test'; 
$VAR2 = { 
      'a' => 1, 
      'b' => 2 
     }; 
$VAR3 = [ 
      'a', 
      'b', 
      'c' 
     ];
2

Vous devrez utiliser un eval, mais cela est généralement considéré comme mauvais. Quelque chose comme:

eval("$glob_var_str = \@_;");

EDIT

juste vérifié que vous ne pouvez le faire sans my et no strict refs.

+2

Mensonges. 'pas de refs strict'. – fennec

+0

Avec 'use strict' ou sans? –

+0

eval peut le faire, mais il y a plus d'une façon de le faire ... vous n'avez pas besoin d'utiliser eval. – Paul

2

Essayez de regarder cette question: Does Perl have PHP-like dynamic variables?

En bref, il semble que vous devriez être en mesure de le faire $$glob_var_str = "whatever";

+0

Vous ne devriez pas avoir de «refs strict» dans le bloc d'abord, cependant. (parce que vous devriez utiliser strict!) – fennec

3
sub create_glob_var { 
    my ($glob_var_str) = @_; 
    no strict 'refs'; 
    $$glob_var_str = undef; # or whatever you want to set it to 
} 

Le no strict 'refs' est nécessaire que si use strict est en vigueur, qu'il toujours devrait être.

Addendum:

Si vous vous demandez s'il y a un moyen d'écrire un sous-programme create_glob_var tel que le code suivant réussira:

use strict; 
create_glob_var("bar"); 
$bar = "whatever"; 

... alors la réponse est « Non » Cependant, vars pragma Perl fera ce que vous voulez:

use strict; 
use vars qw($bar); 
$bar = "whatever"; 

Mais ce genre est de style ancien de codage Perl.De nos jours, on en général faire:

use strict; 
our $bar = "blah"; 

our peut aussi simplement déclarer des variables globales qui peuvent être librement utilisées par la suite:

our ($foo, @bar, %baz); 
# ... 
$foo = 5; 
@bar = (1, 2, 3); 
%baz = (this => 'that'); 
+0

Merci pour la réponse. Cela ne semble pas fonctionner. '' strict'' se plaint au moment de la compilation (?). Voir ma mise à jour post. –

2

Le vars pragma fait déjà le levage de charges lourdes pour ce que vous voulez, si mettre à l'œuvre:

#! /usr/bin/perl 

use warnings; 
use strict; 
use vars; 

BEGIN { vars->import(qw/ $bah /) } 

$bah = "blah"; 
print $bah, "\n"; 

Si vous préférez épeler create_glob_var, puis utilisez

#! /usr/bin/perl 

use warnings; 
use strict; 
use vars; 

sub create_glob_var { vars->import("\$$_[0]") } 

BEGIN { create_glob_var "bah" } 

$bah = "blah"; 
print $bah, "\n"; 

Quoi qu'il en soit, la sortie est

blah

Je suis curieux de savoir pourquoi vous voulez le faire de cette façon plutôt que de déclarer ces variables avec our. Oui, cela peut prendre quelques itérations pour tous les attraper, mais ce sont des corrections à court terme de toute façon, n'est-ce pas?

En général, vous pouvez utiliser une variable comme nom de variable (voir "Symbolic references" in perlref), mais vous avez vraiment, vraiment, vraiment ne veulent pas faire: permettre à la strict 'refs' pragma désactive cette fonction.

Rafael Garcia-Suarez a montré une grande sagesse quand il écrit: « Je ne sais pas ce que votre problème d'origine, mais je suggère d'utiliser un hachage. »

Voir aussi:

+0

La raison pour laquelle je fais tout cela est que quelqu'un a réinventé la roue en créant un analyseur de ligne de commande personnalisé. Il est utilisé dans toute notre pile d'outils. Malheureusement, la méthode actuelle pour déclarer une option consiste à modifier 3 sections de code réparties sur 3000 lignes de code. C'est vraiment horrifiant et cela viole violemment D.R.Y. J'essaie de réduire le besoin de vous répéter dans toute la base de code en collectant d'une manière ou d'une autre tout le code nécessaire pour créer une nouvelle option en moins de 10 lignes de code * contiguë. –

+0

@Ross Le code ci-dessus ne parvient-il pas à faire ce que vous voulez? –

1

Answer by Sinan Unur est en effet le meilleur. Cependant, ceci a capté ma curiosité, donc j'ai fait un peu de lecture (perlocod perldoc) et j'ai appris à propos du hash "package_name ::" pour accéder à l'espace de noms d'un paquet.

Le code suivant ajoute un enregistrement à la table des symboles de main :: package:

use strict; 
my $name = "blah"; 
my $var = "sss"; 
$main::{$name} = \$var; 

print "$main::blah\n"; 

Cette affiche "sss".

Cependant, j'ai dû ajouter le nom du paquet à l'instruction print parce que "use strict" n'est toujours pas dupe.Je vais continuer à chercher - utiliser des vars ne semble pas fonctionner pour le moment.

Questions connexes