[SP-pm] Referências
Luis Motta Campos
luismottacampos at yahoo.co.uk
Sat Nov 15 02:02:08 PST 2008
Daniel de Oliveira Mantovani wrote:
> no caso de uma sub rotina se faz que nem na linha 19, eu sei fazer,
> só que eu não sei o porque!
>
> Alguém pode me dar uma explicação técnica?
Sem comentários sobre você insistir em usar o Deitel. É lamentável, ele
tem vícios e conceitos errados. Você não deveria. Mas é a tua cabeça, e
você parece teimoso.
Sobre referências: o Deitel não explica nada sobre como marcar
variáveis, certo? Assim, você perdeu um conceito importante, que é base
para entender referências.
"$lista", na verdade, é uma abreviação. Formalmente, as variáveis em
Perl são marcadas com os operadores "${}", "@{}", e "%{}". Assim, a
forma "longa" da sintaxe correta de Perl para dizer "$lista", na
verdade, é "${lista}".
Isso é uma herança da implementação do shell, onde a gente pode
manipular os nomes das variáveis sem precisar de uma outra variável para
conter o "nome". Em perl, para fazer isso, podemos usar strings ou
expressões. Por exemplo:
$nome = 'lista';
${ $nome } = [ 1, 2, 3, 4, 5 ]; # mesma coisa que "$lista = ..."
$counter = 1;
${ 'nome' . $counter } = 'valor'; # mesmo que "$nome1 = 'valor';"
Assim, todas as variáveis em Perl tem duas partes distintas: um
"container", que indica o tipo de variável, e um "nome", que vai dentro
do container e especifica qual é entrada da tabela de símbolos do Perl
que eu quero usar.
Oras, referências são simplesmente variáveis que contém um ponteiro para
outro elemento da tabela de símbolos. Ou, em palavras mais simples: uma
variável que contém a parte do "nome" de outra variável. Assim, se eu
quiser, posso aplicar dois containers na mesma variável, em seguida, e
obter o valor referenciado:
@{ ${ lista } } = ( 1, 2, 3, 4, 5 );
Ou, abreviadamente:
@$lista = ( 1, 2, 3, 4, 5 );
Note que o container externo e o container interno são de tipos
diferentes: o Perl não se importa, já que você está falando apenas de
elementos da tabela de símbolos - que são todos definidos pela mesma
estrutura básica.
Assim, podemos também ter uma função que ŕetorna o símbolo que a gente
quer usar:
sub get_list { return $lista }
print @{ get_list() }; # imprime "12345"
# NÃO POSSO abreviar este como
# print @get_list();
# Você sabe dizer por quê? :)
Note que eu precisei usar "()" no nome da função, ou o Perl ficaria
muito confuso e sem saber se o nome que está dentro do container "@{}" é
uma chamada de subrotina ou um nome na tabela de símbolos. Os parêntesis
fazem o perl interpretar aquele nome como uma subrotina automágicamente.
Mas isso ainda não é de-referenciar funções. O que você está
de-referenciando aqui é o valor retornado por uma função.
Para de-referenciar funções, você precisa primeiro saber que funções tem
um tipo e um container também, mas que ele é implícito. O container para
funções pode ser escrito explicitamente como "&{}". ATENÇÃO: por
diversas razões, ao longo do desenvolvimento da linguagem, a gente parou
de escrever "&funcao( $argumento )" e passou a usar a forma mais
flexível "funcao( $argumento )". Assim, usamos o símbolo "&{}" apenas
para falar sobre a entrada na tabela de símbolos correspondente àquela
subrotina. Por exemplo:
sub faz_coisas { return "feito"; }
# para chamar faz_coisas, usamos
$feito = faz_coisas;
# e o perl sabe o que fazer com isso.
Para fazer uma referência para faz_coisas, devemos informar o Perl que
estamos falando explícitamente da entrada na tabela de símbolos, e que
não queremos executar a função. Para isso, usamos o container de subrotina:
$ref_faz_coisas = \ &{ faz_coisas };
Note que eu usei uma "bareword" para indicar o nome da função, o que é
perfeitamente válido. Poderia ter escrito também
$ref_faz_coisas = \ &{ 'faz_coisas' };
Ainda falta um detalhe. Você deve estar se perguntando por que é que o
operador de criação de referência ('\') aparece aqui. Bom, se você
apenas mencionar a entrada na tabela de símbolos para uma função, o
operador de perl vai substituir ela pelo valor, e executar a função para
você.
Isso quer dizer que escrever "&{ faz_coisas }" ou "&{ 'faz_coisas' }"
sem mencionar o operador de referência faz o perl buscar o valor de
'faz_coisas' na tabela de símbolos, e depois resolver a expressão,
executando a função chamada.
Agora temos dois jeitos de armazenar referências para funções: podemos
usar um nome, e forçar um /lookup/ na tabela de símbolos (lento, lento,
lento, mas muito flexível) ou podemos armazenar uma "referência de
verdade" para uma função. Exemplo:
# com um nome e /lookup/:
&{ 'faz_coisas' }( 'argumento1', 'argumento2' );
# ou, com uma referência de verdade:
$ref = \ &faz_coisas; # criando referencia com o operador '\'
$ref->( 'argumento1', 'argumento2' ); # chamando a função
É isso. Agora você sabe por que o Deitel é uma merda: ele não explica
coisas básicas e me faz escrever estes emails longuíssimos.
Espero que isso ajude a entender o que você perguntou.
Putamplexos.
--
Luis Motta Campos is a software engineer,
Perl Programmer, foodie and photographer.
More information about the SaoPaulo-pm
mailing list