Pregunta

Estaba luchando con algunos Perl que usan referencias hash.

Al final resultó que mi problema era la línea:

$myhash{$key} |= {};

Es decir, " asigna $ myhash {$ key} una referencia a un hash vacío, a menos que ya tenga un valor " ;.

Sin embargo, al desreferenciar esto y tratar de usarlo como una referencia hash, se produjeron errores de intérprete sobre el uso de una cadena como referencia hash.

Cambiándolo a:

if( ! exists $myhash{$key}) {
  $myhash{$key} = {};
}

... hizo que las cosas funcionen.

Así que no tengo un problema . Pero tengo curiosidad por lo que estaba pasando.

¿Alguien puede explicar?

¿Fue útil?

Solución

La razón por la que está viendo un error sobre el uso de una cadena como referencia de hash es porque está utilizando el operador incorrecto. | = significa " bitwise-or-assign. " En otras palabras,

  $foo |= $bar;

es lo mismo que

  $foo = $foo | $bar

Lo que está sucediendo en su ejemplo es que su nueva referencia de hash anónima se está estancando, luego se redirige a modo de bits con el valor de $ myhash {$ key} . Para confundir aún más las cosas, si $ myhash {$ key} no está definido en ese momento, el valor es la simple simplificación de la referencia del hash, que se parece a HASH (0x80fc284) . Por lo tanto, si realiza una inspección superficial de la estructura, es posible que parezca como una referencia hash, pero no lo es. Aquí hay algunos resultados útiles a través de Data :: Dumper :

   perl -MData::Dumper -le '$hash{foo} |= { }; print Dumper \%hash'
   $VAR1 = {
             'foo' => 'HASH(0x80fc284)'
           };

Y esto es lo que obtienes cuando usas el operador correcto:

  perl -MData::Dumper -le '$hash{foo} ||= { }; print Dumper \%hash'
  $VAR1 = {
            'foo' => {}
          };

Otros consejos

Perl tiene operadores de asignación de taquigrafía. El operador || = se usa a menudo para establecer valores predeterminados para las variables debido a la característica de Perl de que los operadores lógicos devuelvan el último valor evaluado. El problema es que usaste | = que es un bitwise o en lugar de || = que es un lógico o.

A partir de Perl 5.10 es mejor usar // = en su lugar. // es el operador lógico definido y no falla en el caso de la esquina donde el valor actual está definido pero es falso.

Creo que tu problema estaba usando " | = " (bitwise-o asignación) en lugar de " || = " (Asignar si es falso).

Tenga en cuenta que su nuevo código no es exactamente equivalente. La diferencia es que " $ myhash {$ key} || = {} " reemplazará los valores existentes pero falsos con una referencia de hash, pero la nueva no lo hará. En la práctica, esto probablemente no sea relevante.

Prueba esto:

my %myhash;
$myhash{$key} ||= {};

No puede declarar un elemento hash en una cláusula my , que yo sepa. Primero declara el hash y luego agrega el elemento.

Editar: veo que has eliminado el mi . ¿Qué tal si intentas || = en lugar de | = ? El primero es idiomático para " perezoso " inicialización.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top