Referencias Simbólicas

Lo normal es que una expresión como $$a indique que $a es una variable del tipo referencia a un escalar. Si no fuera el caso, esto es, si $a no fuera una referencia, Perl comprueba si $a contiene una cadena (esto es, la variable está en un contexto escalar cadena) y si es el caso usa esa cadena como nombre de una variable de paquete. Esto se conoce como referenciado simbolico. Su uso es mas eficiente que la alternativa de usar eval. Veamos un ejemplo (obsérvese la ausencia de -w y de use strict):

lhp@nereida:~/Lperl/src/testing$ cat -n symbolicref.pl
 1  #!/usr/bin/perl
 2  sub data {
 3    my ($fa, $sa) = @_;
 4    print "Inside data\n";
 5    print "First list: @$fa\n";
 6    print "Second list: @$sa\n";
 7  }
 8
 9  $data = 4;
10  @data = (1,2,3,4);
11  @tutu = 5..8;
12  $name = "data";
13
14  print "${$name}\n";
15  push  @{$name}, @data;
16  print "@data\n";
17  &{$name}('data', 'tutu');
La ejecución da como resultado:
lhp@nereida:~/Lperl/src/testing$ symbolicref.pl
4
1 2 3 4 1 2 3 4
Inside data
First list: 1 2 3 4 1 2 3 4
Second list: 5 6 7 8

El Pragma strict y el Referenciado Simbólico

El pragma strict impide el uso de referencias simbólicas:

$ cat symbol_ref.pl
#!/usr/bin/perl -w

use strict;

our $x = 4;
my $a = "x";
$$a = 10;

print $x;
$ ./symbol_ref.pl
Can't use string ("x") as a SCALAR ref while "strict refs" in use at ./symbol_ref.pl line 7.

use strict 'refs'

Se puede ser mas específico y restringir solo el uso de referencias simbólicas con use strict 'refs':

$ cat symbol_ref2.pl
#!/usr/bin/perl -w

use strict 'refs';

$x = 4; # no se ha usado our
$a = "x"; # $a tampoco es declarada
$$a = 10;

print $x;
$ ./symbol_ref2.pl
Can't use string ("x") as a SCALAR ref while "strict refs" in use at ./symbol_ref2.pl line 7.

no strict 'refs'

Si, por el contrario, lo que se quiere es permitir el uso de referenciado simbólico en un segmento del programa sin renunciar al control que nos da use strict, debemos usar la cláusula no:

lhp@nereida:~/Lperl/src$ cat -n symbol_ref3.pl
 1  #!/usr/bin/perl -w
 2  use strict;
 3
 4  our ($x, $y, $z) = (4, 5, 6);
 5  my $a = "x";
 6  {
 7    no strict 'refs';
 8    $a = <>;
 9    chomp($a);
10    $$a = 10;
11  }
12
13  print "x=$x, y=$y, z=$z\n";
lhp@nereida:~/Lperl/src$ ./symbol_ref3.pl
z
x=4, y=5, z=10

Referenciado Simbólico y Ámbito de las Variables

Si la cadena sigue las reglas de un nombre completo, Perl utilizará la tabla de símbolos adecuada:

$name = "General::Specific::data";
print ${$name}; # Lo mismo que: print $General::Specific::data;

El Operador Flecha y las Referencias Simbólicas

Las referencias simbólicas tambien pueden usarse a la izquierda del operador ->

$symref = "set";
$symref->{type} = "discrete"; # Lo mismo que: $set->{type} = "discrete";

El pragma strict no protesta del uso de referenciados simbólicos cuando este se hace mediante el operador ->.

Un Ejemplo de uso de Referenciado Simbólico: La función can

El ejemplo que sigue muestra un pequeño intérprete. El usuario llama al programa con un comando y un glob que especifica un conjunto de ficheros.

lhp@nereida:~/Lperl/src/perl_testing_adn_examples/chapter_09$ symbolic.pl dirs /p*
/pendriver
/proc
lhp@nereida:~/Lperl/src/perl_testing_adn_examples/chapter_09$ symbolic.pl latest *
symbolic.pl
lhp@nereida:~/Lperl/src/perl_testing_adn_examples/chapter_09$ symbolic.pl sort_by_time *.pl
symbolic.pl
simplecalc.pl
make_test_files.pl
filefilter.pl
lhp@nereida:~/Lperl/src/perl_testing_adn_examples/chapter_09$ symbolic.pl chuchu *.pl
Unknown command 'chuchu'
Para cada comando el programa implanta una función de filtro e imprime el resultado del filtro.
lhp@nereida:~/Lperl/src/perl_testing_adn_examples/chapter_09$ cat -n symbolic.pl
 1  #!/usr/local/bin/perl
 2  use strict;
 3  use warnings;
 4
 5  main( @ARGV );
 6
 7  sub main {
 8      die "Usage:\n$0 <command> [file_pattern]\n" unless @_;
 9      my $command = shift;
10
11      die "Unknown command '$command'\n" unless  main->can( $command );
12
13      no strict 'refs';
14      my @r = $command->( @_ );
15      local $" = "\n";
16      print "@r\n";
17  }
18
19  sub sort_by_time {
20      map  { $_->[0] }
21      sort { $a->[1] <=> $b->[1] }
22      map  { [ $_, -M $_ ] } @_
23  }
24
25  sub latest {
26      (sort_by_time( @_ ) )[0];
27  }
28
29  sub dirs {
30      grep { -d $_ } @_;
31  }
La principal novedad en este código se refiere al control (línea 11) de que comandos están disponibles. La función can puede ser llamada de la forma:

paquete->can('nombre_de_subrutina')

devuelve cierto si existe una subrutina con ese paquete y falso en caso contrario. De hecho devuelve una referencia (dura/no simbólica) a la subrutina si esta existe.

Recuerde



Subsecciones
Casiano Rodríguez León
2009-10-04