Dificuldade ao construir uma estrutura de dados aninhada

14

Ao tentar criar uma mensagem JSON para uma API, me vi lutando para fazer algo que achava simples. Eu precisava criar uma mensagem como a seguinte:

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

No entanto, minha primeira tentativa não funcionou:

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

Tentar simplificar as coisas me confundiu ainda mais:

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

Então eu tentei usar algumas variáveis ​​temporárias, e isso funcionou:

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

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

O que está acontecendo aqui?

E existe uma maneira de conseguir a saída desejada sem uma variável temporária extra?

jja
fonte
11
say to-json { foo => [ { a => 1 } ] };deve produzir algo como {"foo":[{"a":1}]}, não {"foo":["a":1]}. Este último é um erro de digitação, certo? Se não, o que say $*PERL.compiler.version;diz?
raiph 07/02
Hm, sim, você está certo. Acho que interpretei mal as coisas quando estava tentando coisas. Até say to-json { foo => [ a => 1 ] }resultados, {"foo":[{"a":1}]}para quem sabe o que eu digitei quando recebi, se é que eu já fiz. Foi mal!
jja 8/02

Respostas:

17

Você descobriu a regra do argumento único . Inúmeras construções em Raku irão repetir o argumento fornecido. Isso inclui o [...]compositor da matriz. É por isso que quando dizemos:

say [1..10];

Obtemos uma matriz que contém 10 elementos, não 1. No entanto, isso também significa que:

say [[1,2]];

Itera o [1,2], e, portanto, resulta em [1,2]- como se a matriz interna não estivesse lá. A Hashitera para seus pares, assim:

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

Realmente produz:

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

Ou seja, a matriz possui os pares. O serializador JSON, em seguida, serializa cada par como um objeto de um elemento.

A solução é produzir um elemento único iterável. O ,operador infix é o que produz listas, para que possamos usar isso:

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

Em seguida, o único argumento a ser iterado é uma lista de 1 elemento com um hash e você obtém o resultado desejado.

Maneira fácil de lembrá-lo: sempre use vírgulas finais ao especificar os valores de uma lista, matriz ou hash, mesmo com uma lista de elemento único, a menos que você esteja especificando a iterável única a partir da qual será preenchida.

Jonathan Worthington
fonte
2
A outra maneira é discriminar em um escalar: {foo => [$ {a => 1, b => 2}]}
jakar