Difficulté lors de la construction d'une structure de données imbriquée

14

En essayant de créer un message JSON pour une API, j'ai eu du mal à faire quelque chose que je pensais être simple. J'avais besoin de créer un message comme celui-ci:

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

Cependant, ma première tentative n'a pas fonctionné:

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

Essayer de simplifier les choses m'a encore plus dérouté:

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

Ensuite, j'ai essayé d'utiliser des variables temporaires, et cela a fonctionné:

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 se passe t-il ici?

Et est-il possible d'obtenir la sortie souhaitée sans variable temporaire supplémentaire?

jja
la source
1
say to-json { foo => [ { a => 1 } ] };devrait produire quelque chose comme {"foo":[{"a":1}]}, non {"foo":["a":1]}. Ce dernier est une faute de frappe, non? Sinon, que say $*PERL.compiler.version;dit-on?
raiph
Hm, ouais, tu as raison. Je suppose que j'ai mal lu les choses quand j'essayais des trucs. Même say to-json { foo => [ a => 1 ] }sorties {"foo":[{"a":1}]}donc qui sait ce que j'ai tapé quand j'ai eu ça, si je l'ai jamais fait. Ma faute!
jja

Réponses:

17

Vous avez découvert la règle de l'argument unique . De nombreuses constructions dans Raku répéteront l'argument qui leur est fourni. Cela inclut le [...]compositeur de tableaux. C'est pourquoi quand on dit:

say [1..10];

Nous obtenons un tableau qui contient 10 éléments, pas 1. Cependant, cela signifie également que:

say [[1,2]];

Itère le [1,2], et entraîne donc [1,2]- comme si le tableau interne n'était pas là. A Hashitère ses paires, donc:

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

Produit réellement:

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

Autrement dit, le tableau a les paires. Le sérialiseur JSON sérialise ensuite chaque paire en tant qu'objet à un élément.

La solution est de produire un itérable à un seul élément. L' ,opérateur infixe est ce qui produit les listes, nous pouvons donc l'utiliser:

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

Ensuite, le seul argument à itérer est une liste à 1 élément avec un hachage, et vous obtenez le résultat souhaité.

Un moyen facile de s'en souvenir: utilisez toujours des virgules de fin lorsque vous spécifiez les valeurs d'une liste, d'un tableau ou d'un hachage, même avec une seule liste d'éléments, à moins que vous ne spécifiiez réellement le seul itérable à partir duquel le remplir.

Jonathan Worthington
la source
2
L'autre façon est de détailler dans un scalaire: {foo => [$ {a => 1, b => 2}]}
jakar