Dificultad al construir una estructura de datos anidada

14

Al intentar crear un mensaje JSON para una API, me encontré luchando por hacer algo que pensé que sería simple. Necesitaba crear un mensaje como el siguiente:

{ "list": [ { "foo": 1, "bar": 2 } ] }

Sin embargo, mi primer intento no funcionó:

say to-json { foo => [ { a => 1, b => 2 } ] };
# {"foo":[{"a":1},{"b":2}]}

Intentar simplificar las cosas me confundió aún más:

say { foo => [ { a => 1 } ] };
# {foo => [a => 1]}
# Note that this is not JSON, but I expected to see curly braces

Luego intenté usar algunas variables temporales, y eso funcionó:

my @list = { a => 1 };
say to-json { foo => @list };
# {"foo":[{"a":1}]}

my %hash = ( a => 1 );
say to-json { foo => [ %hash ] };
# {"foo":[{"a":1}]}

¿Que está pasando aqui?

¿Y hay alguna manera de lograr el resultado deseado sin una variable temporal adicional?

jja
fuente
1
say to-json { foo => [ { a => 1 } ] };debería mostrar algo como {"foo":[{"a":1}]}, no {"foo":["a":1]}. Este último es un error tipográfico, ¿verdad? Si no, ¿qué say $*PERL.compiler.version;dice?
raiph
Hm, sí, tienes razón. Supongo que leí mal las cosas cuando estaba probando cosas. Incluso say to-json { foo => [ a => 1 ] }salidas, {"foo":[{"a":1}]}así que quién sabe lo que escribí cuando lo obtuve, si alguna vez lo hice. ¡Culpa mía!
jja

Respuestas:

17

Has descubierto la regla del argumento único . Numerosas construcciones en Raku iterarán el argumento que se les proporciona. Esto incluye el [...]compositor de matrices. Es por eso que cuando decimos:

say [1..10];

Obtenemos una matriz que contiene 10 elementos, no 1. Sin embargo, también significa que:

say [[1,2]];

Itera el [1,2], y por lo tanto resulta en [1,2]- como si la matriz interna no estuviera allí. A Hashitera a sus pares, por lo tanto:

{ foo => [ { a => 1, b => 2 } ] }

Actualmente produce:

{ foo => [ a => 1, b => 2 ] }

Es decir, la matriz tiene los pares. El serializador JSON serializa cada par como un objeto de un elemento.

La solución es producir un elemento único iterable. El ,operador infijo es lo que produce listas, por lo que podemos usar eso:

say to-json { foo => [ { a => 1, b => 2 }, ] };
#                        note the , here ^

Entonces, el argumento único que debe iterarse es una lista de 1 elemento con un hash, y obtiene el resultado que desea.

Una forma fácil de recordarlo: siempre use comas finales al especificar los valores de una lista, matriz o hash, incluso con una lista de elementos únicos, a menos que realmente esté especificando el único iterable desde el cual llenarlo.

Jonathan Worthington
fuente
2
La otra forma es detallar en un Escalar: {foo => [$ {a => 1, b => 2}]}
jakar