Trudność przy konstruowaniu zagnieżdżonej struktury danych

14

Podczas próby utworzenia komunikatu JSON dla interfejsu API miałem trudności z zrobieniem czegoś, co moim zdaniem byłoby proste. Musiałem utworzyć wiadomość podobną do następującej:

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

Jednak moja pierwsza próba nie zadziałała:

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

Próba dalszego uproszczenia sprawiła mi więcej zamieszania:

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

Potem spróbowałem użyć zmiennych tymczasowych i to zadziałało:

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

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

Co tu się dzieje?

I czy jest sposób, w jaki mogę osiągnąć pożądaną wydajność bez dodatkowej zmiennej tymczasowej?

jja
źródło
1
say to-json { foo => [ { a => 1 } ] };powinien wypisać coś takiego {"foo":[{"a":1}]}, a nie {"foo":["a":1]}. Ten ostatni to literówka, prawda? Jeśli nie, co say $*PERL.compiler.version;powiesz?
raiph
Hmm, tak, masz rację. Chyba źle odczytałem, kiedy próbowałem. Nawet dane say to-json { foo => [ a => 1 ] }wyjściowe, {"foo":[{"a":1}]}więc kto wie, co napisałem, kiedy to dostałem, jeśli kiedykolwiek to zrobiłem. Mój błąd!
jja

Odpowiedzi:

17

Pan odkrył zasadę jeden argument . Liczne konstrukcje w Raku będą iterować argument, którym je dostarczono. Obejmuje to [...]kompozytora tablicowego. Właśnie dlatego, gdy mówimy:

say [1..10];

Otrzymujemy tablicę zawierającą 10 elementów, a nie 1. Oznacza to jednak, że:

say [[1,2]];

Iteruje [1,2], a zatem skutkuje [1,2]- tak jakby nie było tablicy wewnętrznej. HashIteracje swoich par, a więc:

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

Faktycznie produkuje:

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

Oznacza to, że tablica ma pary. Serializator JSON serializuje następnie każdą parę jako obiekt jednoelementowy.

Rozwiązaniem jest utworzenie iterowalnego elementu. ,Operator infix tworzy listy, więc możemy użyć tego:

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

Wówczas jedynym argumentem, który ma być iterowany, jest lista 1-elementowa z skrótem i otrzymujesz pożądany wynik.

Łatwy sposób na zapamiętanie: zawsze używaj przecinków końcowych przy określaniu wartości listy, tablicy lub skrótu, nawet z listą pojedynczych elementów, chyba że tak naprawdę określasz pojedynczy iterowalny element, z którego chcesz ją wypełnić.

Jonathan Worthington
źródło
2
Innym sposobem jest wyszczególnienie w Skalarach: {foo => [$ {a => 1, b => 2}]}
jakar