2010-02-16 9 views
7

In Perl, è possibile creare una variabile globale basata su una stringa?Come posso creare un nome di variabile Perl basato su una stringa?

esempio se ho avuto una funzione come:

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

e ho chiamato come:

create_glob_var("bar"); 

Come potrei modificare create_glob_var per creare effettivamente una variabile globale chiamata $bar?

Il mio progetto utilizza perl 5.8.5.

EDIT

Quanto segue non funziona:

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 mi rendo conto che l'utilizzo di variabili globali provoca ozone depletion and male pattern baldness. Sto cercando di ripulire un codice legacy che è già completamente infetto dall'uso di variabili globali. Un refactoring alla volta ...

+0

La subroutine crea la variabile globale, ma è comunque necessario accedervi in ​​un modo accettabile per strict, probabilmente uno di 1) $ My :: Package :: bah = "blah", 2) usa vw qw ($ bah); $ bah = "blah", o 3) il nostro $ bah = "blah". – Sean

+4

Non fare cose del genere. vedi http://stackoverflow.com/questions/1549685/how-can-i-use-a-variable-as-a-variable-name-in-perl –

+0

concordato. Utilizzare un hash globale per memorizzare i dati (se è necessario utilizzare globalmente), piuttosto che creare nuovi scalari! – Ether

risposta

5

Se yo stai cercando di ripulire il vecchio codice, puoi scrivere un modulo che esporta le variabili richieste. Ogni volta che senti la necessità di invocare create_glob_var, aggiungi una variabile a questo pacchetto e inseriscila nell'elenco di importazione.

Ciò consente di tenere traccia di ciò che sta accadendo e di come vengono utilizzate le variabili.

package MyVars; 

use strict; use warnings; 

use Exporter 'import'; 

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

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

Lo 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); 

uscita:

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

Dovresti usare uno eval, ma generalmente è considerato malvagio. Qualcosa di simile:

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

EDIT

Proprio verificato che si può fare solo questo senza l'my e con no strict refs.

+2

Bugie. 'no refs rigorosi'. – fennec

+0

Con 'use strict' o without? –

+0

eval può farlo, ma c'è più di un modo per farlo ... non devi usare eval. – Paul

2

Prova a guardare questa domanda: Does Perl have PHP-like dynamic variables?

In breve, sembra che si dovrebbe essere in grado di fare $$glob_var_str = "whatever";

+0

Per prima cosa dovresti "no strict refs" nel blocco. (perché dovresti usare rigorosamente!) – 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 
} 

L'no strict 'refs' è necessario solo se use strict è a tutti gli effetti, che sempre dovrebbe essere.

Addendum:

Se stai chiedendo se c'è un modo per scrivere una subroutine create_glob_var tale che il seguente codice avrà successo:

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

... allora la risposta è "no" Tuttavia, vars pragma di Perl farà ciò che si vuole:

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

Ma questo è una specie di vecchio stile di codifica Perl.Al giorno d'oggi, si potrebbe in genere fare questo:

use strict; 
our $bar = "blah"; 

our può anche solo dichiarare le variabili globali che possono essere utilizzati liberamente in seguito:

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

Grazie per la risposta. Non sembra funzionare. '' strict'' si lamenta al momento della compilazione (?). Vedi il mio post aggiornato. –

2

Il vars pragma già fa il lavoro pesante per quello che vuoi, in modo mettere al lavoro:

#! /usr/bin/perl 

use warnings; 
use strict; 
use vars; 

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

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

Se si preferisce scriverlo create_glob_var, quindi utilizzare

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

In entrambi i casi, l'uscita è

blah

Sono curioso di sapere perché si vuole fare in questo modo piuttosto che dichiarare queste variabili con our. Sì, potrebbero essere necessarie alcune iterazioni per catturarle tutte, ma queste sono comunque correzioni a breve termine, giusto?

In generale, è possibile utilizzare una variabile come un nome di variabile (vedi "Symbolic references" in perlref), ma è davvero, davvero, davvero non vogliono fare questo: consentire la strict 'refs' pragma disabilita questa funzione.

Rafael Garcia-Suarez ha mostrato grande saggezza quando ha scritto: “Io non so che cosa il vostro problema originale è, ma vi suggerisco di utilizzare un hash.”

Vedi anche:

+0

Il motivo per cui sto facendo tutto questo è qualcuno che ha reinventato la ruota creando un parser da riga di comando personalizzato. È usato in tutta la nostra pila di attrezzi. Sfortunatamente, il metodo corrente per dichiarare un'opzione comporta la modifica di 3 sezioni di codice distribuite su 3000 righe di codice. È davvero orribile e viola violentemente D.R.Y. Sto cercando di ridurre la necessità di ripeterti nell'intero codice base raccogliendo in qualche modo tutto il codice necessario per creare una nuova opzione in meno di 10 righe di codice * contiguo *. –

+0

@Ross Il codice sopra non riesce a fare ciò che vuoi? –

1

risposta da Sinan Unur è davvero il migliore. Tuttavia, ciò ha attirato la mia curiosità, quindi ho fatto un po 'di lettura (perldoc perlmod) e ho imparato a conoscere l'hash "package_name ::" come modo per accedere allo spazio dei nomi di un pacchetto.

Il codice seguente aggiunge un record alla tabella dei simboli del principale :: pacchetto:

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

print "$main::blah\n"; 

Questa "sss" stampe.

Tuttavia, ho dovuto aggiungere il nome del pacchetto all'istruzione di stampa perché "use strict" non è ancora ingannato.Continuerò a cercare - usare Vars non sembra funzionare al momento.

Problemi correlati