Сложность при построении вложенной структуры данных

14

Пытаясь создать сообщение JSON для API, я столкнулся с трудностями, пытаясь сделать что-то, что, на мой взгляд, было бы простым. Мне нужно было создать сообщение, подобное следующему:

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

Однако моя первая попытка не сработала:

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

Попытка упростить вещи еще больше смутила меня:

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

Затем я попытался использовать некоторые временные переменные, и это сработало:

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

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

Что тут происходит?

И есть ли способ, которым я могу достичь желаемого результата без дополнительной временной переменной?

JJA
источник
1
say to-json { foo => [ { a => 1 } ] };должен выводить что-то вроде {"foo":[{"a":1}]}, нет {"foo":["a":1]}. Последняя опечатка, верно? Если нет, что say $*PERL.compiler.version;говорит?
raiph
Хм, да, ты прав. Я думаю, что я неправильно прочитал вещи, когда я пытался что-то делать. Даже say to-json { foo => [ a => 1 ] }результаты, {"foo":[{"a":1}]}так что, кто знает, что я напечатал, когда я получил это, если я когда-либо сделал. Виноват!
JJA

Ответы:

17

Вы обнаружили правило с одним аргументом . Многочисленные конструкции в Raku будут повторять аргумент, который им предоставляется. Это включает в себя [...]массив композитора. Вот почему, когда мы говорим:

say [1..10];

Мы получаем массив, который содержит 10 элементов, а не 1. Однако это также означает, что:

say [[1,2]];

Итерирует [1,2], и, следовательно, приводит к [1,2]- как если бы внутреннего массива не было. A Hashперебирает свои пары, таким образом:

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

На самом деле производит:

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

То есть в массиве есть пары. Сериализатор JSON затем сериализует каждую пару как одноэлементный объект.

Решение состоит в том, чтобы создать итерацию из одного элемента. Инфиксный ,оператор - это то, что создает списки, поэтому мы можем использовать это:

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

Тогда единственный аргумент, который должен быть повторен - это 1-элементный список с хешем, и вы получите желаемый результат.

Простой способ запомнить это: всегда используйте конечные запятые при указании значений списка, массива или хеша, даже с одним списком элементов, если вы на самом деле не указываете единственную итерацию, из которой нужно заполнить ее.

Джонатан Уортингтон
источник
2
Другой способ - перечислить в скаляр: {foo => [$ {a => 1, b => 2}]}
Джакар