[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