[Perl] Pasando un hash (entregado por un método) a keys

Salvador Ortiz Garcia sog@msg.com.mx
Fri, 22 Aug 2003 14:48:15 -0500


On Fri, 2003-08-22 at 10:37, Gunnar Wolf wrote:
> Hola,
> 
> Esta me tiene completamente en blanco, espero que alguno de ustedes
> pueda echarme una mano: Tengo una función que regresa un hash:

Las funciones en perl _no_ pueden regresar hashes! (solo escalares o
listas de los mismos).

Cuando perl evalúa %foo, lo que haces es generar la lista
correspondiente de llaves/valores que por supuesto puede ser reasignada
a un hash.

> 
>     return map { $_=>$authors->{$_}->{'mention_order'} } keys %$authors;

Esto regresa una lista, no un hash!

> 
> Ahora, en determinado punto quiero usar únicamente las llaves,
> descartando los valores. Me funciona así:
> 
> my %tmp = get_authors;
Asignas la lista a un hash, lo que funciona
> my @authors = keys %tmp;
> 
> Pero, obviamente, se ve horrible, y no me gusta estar creando variables
> innecesarias. Ahora, si hago:
> 
> my @authors = keys(get_authors());
A keys les estás enviando una lista, no un hash!

> Perl me dice que:
> 
> Type of arg 1 to keys must be hash (not subroutine entry)
> 
> De hecho, hice un one-liner para demostrar la generalidad de esta bronca:
> 
> $ perl -e 'sub dameHash {my %h=(1=>2,3=>4); return %h}; print keameHash'

Igual, tu dameHash regresa una lista.

> Type of arg 1 to keys must be hash (not subroutine entry) at -e line 1, at EOF
> Execution of -e aborted due to compilation errors.
> 
> O sea que... ¡Ni siquiera llega a evaluarlo! :-( keys necesita, a tiempo
> de compilación, ir junto a un hash real - ¿Por qué?

La sintaxis es 'keys HASH' y no 'keys LIST'
> 
> ¿Hay alguna manera de sacarle la vuelta a esto, que suena tan poco Pérlico?

Sólo suena ;-)  Muchas funciones internas de perl son lo que en Lisp se
llaman "special forms", es decir, no usan (y no pueden usar) el
mecanismo normal de paso de parámetros, en perl son las "no
prototipeables" (TM de Matías Software)

Una posibilidad es crear un hash real y regresarlo por referencia, pero
tu keys requiere dereferenciarlo:

  sub dameRefHash { my %h=(1=>2,3=>4); \%h }; 
  print keys %{dameRefHash()};

O en version cortita (hash anónimo):

  sub dameRefHash { {1=>2,3=>4} };
  print keys %{dameRefHash()};

En tu ejemplo original, se me ocurre:

 return {map { $_=>$authors->{$_}->{'mention_order'} } keys %$authors};

seguido de:

 my @authors = keys %{get_authors()};

Por otro lado si no quieres regresar referencias, sino las listas
(gastando más memoria), tambien te funciona:

  print keys %{{dameHash()}};

Saludos
-- 
Salvador Ortiz Garcia <sog@msg.com.mx>
Matías Software Group