Pergunta

Em Perl, é possível criar uma variável global baseada em uma string?

Por exemplo, se eu tivesse uma função como:

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

e eu chamei assim:

create_glob_var( "bar" );

Como eu poderia modificar create_glob_var para realmente criar uma variável global chamada $bar?

Meu projeto está usando Perl 5.8.5.

EDITAR

O seguinte não 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";

Produz:

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.

OBSERVAÇÃO Eu percebo que o uso de variáveis ​​globais causa destruição da camada de ozônio e calvície masculina.Estou tentando limpar algum código legado que já está completamente infectado com o uso de variáveis ​​globais.Uma refatoração de cada vez...

Foi útil?

Solução

Se você estiver tentando limpar código antigo, poderá escrever um módulo que exporte as variáveis ​​necessárias.Toda vez que você sentir a necessidade de invocar create_glob_var, em vez disso, adicione uma variável a este pacote e coloque-a na lista de importação.

Isso o ajudará a acompanhar o que está acontecendo e como as variáveis ​​estão sendo usadas.

package MyVars;

use strict; use warnings;

use Exporter 'import';

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

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

O roteiro:

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

Saída:

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

Outras dicas

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

O no strict 'refs' só é necessário se use strict está em vigor, o que sempre deveria estar.

Termo aditivo:

Se você está perguntando se existe uma maneira de escrever uma sub-rotina create_glob_var de modo que o seguinte código seja bem-sucedido:

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

... então a resposta é "Não." No entanto, Perl's vars pragma fará o que você quiser:

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

Mas isso é uma espécie de codificação Perl à moda antiga.Hoje em dia, normalmente alguém faria isso:

use strict;
our $bar = "blah";

our também pode simplesmente declarar variáveis ​​globais que podem ser usadas livremente mais tarde:

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

Tente olhar para esta questão:Perl possui variáveis ​​dinâmicas semelhantes ao PHP?

Em resumo, parece que você deveria ser capaz de fazer $$glob_var_str = "whatever";

Você teria que usar um eval, mas isso geralmente é considerado mau.Algo como:

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

EDITAR

Acabei de verificar que você só pode fazer isso sem o my e com no strict refs.

O vars o pragma já faz o trabalho pesado para o que você deseja, então coloque-o para funcionar:

#! /usr/bin/perl

use warnings;
use strict;
use vars;

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

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

Se você preferir soletrar create_glob_var, então use

#! /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 qualquer forma, a saída é

blah

Estou curioso para saber por que você quer fazer desta forma, em vez de declarar essas variáveis ​​com our.Sim, podem ser necessárias algumas iterações para capturar todos eles, mas de qualquer maneira, essas são soluções de curto prazo, certo?

Em geral, você pode usar uma variável como nome de variável (veja "Referências simbólicas" em perlref), mas você realmente, realmente, realmente não quero fazer isso:habilitando o strict 'refs' pragma desativa esse recurso.

Rafael Garcia-Suarez demonstrou grande sabedoria ao escrever: “Não sei qual é o seu problema original, mas sugiro usar um hash”.

Veja também:

Resposta de Sinan Ünür é realmente a melhor.No entanto, isso despertou minha curiosidade, então li um pouco (perldoc perlmod) e aprendi sobre o hash "package_name::" como forma de acessar o namespace de um pacote.

O código a seguir adiciona um registro à tabela de símbolos de main::pacote:

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

print "$main::blah\n";

Isso imprime "sss".

No entanto, tive que adicionar o nome do pacote à instrução print porque "use strict" ainda não é enganado.Vou continuar procurando - usar vars parece não funcionar no momento.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top