2010-02-16 13 views
7

En Perl, ¿es posible crear una variable global basada en una cadena?¿Cómo puedo crear un nombre de variable Perl basado en una cadena?

por ejemplo, si tuviera una función como:

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

y lo llamé gustaría:

create_glob_var("bar"); 

¿Cómo podría modificar create_glob_var para realmente crear una variable global llamada $bar?

Mi proyecto está utilizando perl 5.8.5.

EDITAR

El siguiente no funciona:

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

Produce:

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.

NOTA que darse cuenta de que el uso de variables globales hace que ozone depletion and male pattern baldness. Estoy tratando de limpiar algún código heredado que ya está completamente infectado con el uso de variables globales. Un refactor a la vez ...

+0

La subrutina crea la variable global, pero aún necesita acceder de manera aceptable a estricta, probablemente una de 1) $ My :: Package :: bah = "blah", 2) use vars qw ($ bah); $ bah = "blah", o 3) nuestro $ bah = "blah". – Sean

+4

No hagas cosas como esta. ver http://stackoverflow.com/questions/1549685/how-can-i-use-a-variable-as-a-variable-name-in-perl –

+0

De acuerdo. Use un hash global para almacenar datos (si debe usar globales), ¡en lugar de crear nuevos escalares! – Ether

Respuesta

5

Si yo Está tratando de limpiar el código anterior, puede escribir un módulo que exporte la (s) variable (s) requerida (s). Cada vez que sienta la necesidad de invocar create_glob_var, agregue una variable a este paquete y póngalo en la lista de importación.

Esto le ayudará a realizar un seguimiento de lo que está sucediendo y cómo se utilizan las variables.

package MyVars; 

use strict; use warnings; 

use Exporter 'import'; 

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

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

El guión:

#!/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); 

Salida:

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

Tendría que usar un eval, pero eso generalmente se considera malo. Algo así como:

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

EDITAR

Sólo verifica que sólo se puede hacer esto sin la my y con no strict refs.

+2

Mentiras. 'no hay referencias estrictas'. – fennec

+0

Con 'use strict' o sin? –

+0

eval puede hacerlo, pero hay más de una forma de hacerlo ... no tiene que usar eval. – Paul

2

Trate de mirar a esta pregunta: Does Perl have PHP-like dynamic variables?

En resumen, parece que usted debería ser capaz de hacer $$glob_var_str = "whatever";

+0

Sin embargo, no debe 'refs estrictos' en el bloque primero. (porque debe usar estricto!) – 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 
} 

El no strict 'refs' sólo es necesario si use strict es, en efecto, que siempre debiera ser.

Adición:

Si estás preguntando si hay una manera de escribir una subrutina create_glob_var de tal manera que el siguiente código tendrá éxito:

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

... entonces la respuesta es "No" Sin embargo, vars pragma de Perl va a hacer lo que quiere:

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

Pero esto es una especie de viejo estilo Perl codificación.Hoy en día, uno puede normalmente hacer esto:

use strict; 
our $bar = "blah"; 

our también puede declarar variables globales que pueden ser utilizados libremente después:

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

Gracias por la respuesta. No parece estar funcionando. '' strict'' se queja en el momento de la compilación (?). Ver mi publicación actualizada. –

2

El pragma vars ya lo hace el trabajo pesado por lo que quieres, por lo ponerla a trabajar:

#! /usr/bin/perl 

use warnings; 
use strict; 
use vars; 

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

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

Si prefiere deletrearlo create_glob_var, a continuación, utilizar

#! /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"; 

De cualquier manera, la salida es

blah

Tengo curiosidad por saber por qué desea hacerlo de esta manera en lugar de declarar estas variables con our. Sí, puede llevar algunas iteraciones atraparlos a todos, pero de todos modos se trata de soluciones a corto plazo, ¿no?

En general, se puede utilizar una variable como un nombre de variable (ver "Symbolic references" in perlref), pero que realmente, realmente, realmente no quieren hacer eso: permitir el pragma strict 'refs' desactiva esta función.

Rafael García-Suárez mostró gran sabiduría cuando escribió: “No sé cuál es su problema original es, pero sugiero utilizar un hash”.

Ver también:

+0

La razón por la que estoy haciendo todo esto es que alguien reinventó la rueda creando un analizador de línea de comando personalizado. Se usa en toda nuestra pila de herramientas. Desafortunadamente, el método actual para declarar una opción implica modificar 3 secciones de código repartidas en 3000 líneas de código. Es realmente horrible y viola violentamente D.R.Y. Estoy tratando de reducir la necesidad de repetirlo en toda la base de códigos recopilando de algún modo todo el código necesario para crear una nueva opción en menos de 10 líneas de * código * contiguo. –

+0

@Ross ¿El código anterior no hace lo que usted quiere? –

1

respuesta de Sinan Unur es sin duda la mejor. Sin embargo, esto recogió mi curiosidad, así que leí un poco (perldoc perlmod) y aprendí sobre el hash "package_name ::" como una forma de acceder al espacio de nombres de un paquete.

El siguiente código añade un registro a la tabla de símbolos del paquete principal :::

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

print "$main::blah\n"; 

Este "sss" impresiones.

Sin embargo, tuve que agregar el nombre del paquete a la declaración de impresión porque "use strict" todavía no se deja engañar.Seguiré buscando: usar vars no parece funcionar en este momento.

Cuestiones relacionadas