Pergunta

Por que o trecho a seguir funciona?E que mal poderia ser possível usando isso?Mas, falando sério, há alguma razão para o código em ${} é avaliado e depois usado como referência escalar?

use strict;
no strict 'refs';

our $message = "Hello world!";
print "${ lc 'MESSAGE' }\n";
Foi útil?

Solução

Tudo bem, A menos que você use referências simbólicas. Suponha que o seguinte código:

my %messages = (hello => "Hello world!", bye => "Bye-bye, world!");
sub get_message_ref { return \$messages{$_[0]} }; # returns scalarref
print "${ get_message_ref('bye') }\n";

Concordo, sua utilidade não é óbvia nos escalares, mas é muito útil com o ArrayRefs.

print "keys: @{[keys %messages]}\n";

Outras dicas

Explicamos isso em profundidade em Perl intermediário.

A sintaxe geral para pesquisas de variáveis ​​é:

 SIGIL  BLOCK  INDEXY-THING

Para um escalar simples parecido com:

 print $   { foo };

Você provavelmente já viu isso quando precisa separar o nome de uma variável das coisas que a cercam:

 print "abc${foo}def\n";

Se você tiver apenas um identificador Perl no bloco e nenhuma bagunça ao redor, poderá deixar de lado os colchetes, que é o caso comum:

 print $foo;

No entanto, é a mesma coisa para desreferenciar uma referência:

 SIGIL  BLOCK-RETURNING-REFERENCE  INDEXY-THINGS

Se o que você obtém no bloco é uma referência, Perl tenta desreferencia-lo como você pediu também:

 my $ref = \ '12345';
 print $     { $ref };

Mas isso é um verdadeiro bloqueio, e não apenas açúcar.Você pode ter quantas declarações quiser lá:

 print $     { my $ref = \ '1234'; $ref };

Agora você não está apenas especificando um identificador Perl, então o Perl não assume que você está fornecendo um identificador e executa o código e usa o resultado como referência.Considere a diferença entre estes quase idênticos say declarações:

    use 5.010;
our $foo = "I'm the scalar";

sub foo { \ "I'm the sub" }

say ${foo};
say ${foo;};

Naquele segundo say Perl vê o ponto e vírgula, percebe que não é um identificador, interpreta o código entre colchetes como texto e retorna o resultado.Como o resultado é uma referência, ele usa o ${...} para desreferencia-lo.Não importa onde você faz isso, então fazê-lo dentro de uma string entre aspas duplas não é especial.

Além disso, observe o our lá.Isso é importante agora que você considerará algo um pouco mais complicado:

    use 5.010;
our $foo = "I'm the scalar";

sub foo { \ "I'm the sub" }
sub baz { 'foo' }

say ${foo};
say ${foo;};
say ${baz;};

Perl interpreta o que dura say como código e vê o resultado não é uma referência;é a string simples foo.Perl vê que não é uma referência, mas agora está em um contexto de desreferenciação, então faz uma referência simbólica (como Greg Bacon descreve).Como as referências simbólicas funcionam com variáveis ​​na tabela de símbolos, isso $foo tinha que ser uma variável de pacote.

Já que é fácil bagunçar tudo, strict tem uma verificação útil para isso.Porém, ao desligá-lo, não se surpreenda quando ele te morder.:)

De Seção "Usando referências" da documentação de Perlref:

Em qualquer lugar que você colocasse um identificador (ou cadeia de identificadores) como parte de uma variável ou nome da sub -rotina, você pode substituir o identificador por um bloco retornando uma referência do tipo correto. Em outras palavras, os exemplos anteriores podem ser escritos assim:

$bar = ${$scalarref};
push(@{$arrayref}, $filename);
${$arrayref}[0] = "January";
${$hashref}{"KEY"} = "VALUE";
&{$coderef}(1,2,3);
$globref->print("output\n");  # iff IO::Handle is loaded

É certo que é um pouco bobo usar os enrolados neste caso, mas o bloco pode conter qualquer expressão arbitrária, em particular, expressões subcritivas:

&{ $dispatch{$index} }(1,2,3);    # call correct routine

Por ser capaz de omitir os enrolados pelo caso simples de $$x, as pessoas geralmente cometem o erro de ver os símbolos de desreferência como operadores adequados e se perguntam sobre sua precedência. Se fossem, porém, você poderia usar parênteses em vez de aparelhos. Esse não é o caso. Considere a diferença abaixo; O caso 0 é uma versão curta do caso 1, não o caso 2:

$$hashref{"KEY"}   = "VALUE";     # CASE 0
${$hashref}{"KEY"} = "VALUE";     # CASE 1
${$hashref{"KEY"}} = "VALUE";     # CASE 2
${$hashref->{"KEY"}} = "VALUE";   # CASE 3

O caso 2 também é enganoso, pois você está acessando uma variável chamada %hashref, não desreferenciando $hashref Para o hash, presumivelmente está referenciando. Esse seria o caso 3.

Mais tarde em "Referências simbólicas":

Dissemos que as referências surgem em existência, conforme necessário, se estiverem indefinidas, mas não dissemos o que acontece se um valor usado como referência já estiver definido, mas não é uma referência difícil. Se você o usar como referência, ele será tratado como uma referência simbólica. Ou seja, o valor do escalar é considerado o nome de uma variável, em vez de um link direto para um valor (possivelmente) anônimo.

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