Raku HTTP 클라이언트 요청에서 JSON 추출

Nov 26 2020

이 Raku 코드의 문제점을 이해하는 데 어려움이 있습니다.

웹 사이트에서 JSON을 가져 와서 JSON 내의 배열 (이 경우 Discourse 포럼의 최신 주제 제목)에있는 각 항목의 필드를 인쇄하고 싶습니다.

이것은 내가 작동 할 것으로 예상 한 코드이지만 실패했습니다.

use HTTP::UserAgent;
use JSON::Tiny;

my $client = HTTP::UserAgent.new; $client.timeout = 10;

my $url = 'https://meta.discourse.org/latest.json'; my $resp = $client.get($url);

my %data = from-json($resp.content); # I think the problem starts here. my @topics = %data<topic_list><topics>; say @topics.WHAT; #=> (Array) for @topics -> $topic {
    say $topic<fancy_title>;
}

오류 메시지는 다음 say $topic<fancy_title>줄 에서 나옵니다 .

Type Array does not support associative indexing.
  in block <unit> at http-clients/http.raku line 18

해시 배열이기 때문에 $topic로 작성되어야한다고 예상 %topic했지만 작동하지 않습니다.

for @topics -> %topic {
    say %topic<fancy_title>;
}

이에 대한 오류 메시지는 다음과 같습니다.

Type check failed in binding to parameter '%topic'; expected Associative but got Array ([{:archetype("regula...)
  in block <unit> at http-clients/http.raku line 17

데이터를 검사하는 경우 배열이 아니라 해시 여야합니다. 나는 시도 @array하지만이 변경 그래서, 즉 정확하지 알고 %topic$topic.

나는 마지막으로 추가하여 작업에있어 .list정의하는 라인에 @topics있지만, 때문에 나는, 왜 수정을 이해하지 못하는 @topics입니다 (Array)즉 추가 여부.

다음은 작동 코드입니다.

use HTTP::UserAgent;
use JSON::Tiny;

my $client = HTTP::UserAgent.new; $client.timeout = 10;

my $url = 'https://meta.discourse.org/latest.json'; my $resp = $client.get($url);

my %data = from-json($resp.content); # Adding `.list` here makes it work, but the type doesn't change. # Why is `.list` needed? my @topics = %data<topic_list><topics>.list; say @topics.WHAT; #=> (Array) # Why is it `$topic` instead of `%topic`?
for @topics -> $topic { say $topic<fancy_title>;
}

실패한 이유와이 작업을 수행하는 올바른 방법을 아는 사람이 있습니까?

답변

8 user0721090601 Nov 26 2020 at 07:06

무슨 일이 일어 났는지 말할 때 배열의 배열을 만들었습니다.

my @topics = %data<topic_list><topics>;

이것은 이러한 모듈에 고유하지 않지만 배열 할당이있는 Raku 전반에 걸쳐 일반적입니다.

무슨 일이 일어나는지보기 위해 더 간단한 해시를 봅시다 :

my %x = y => [1,2,3];

my $b = %x<y>; my @b = %x<y>; say $b;  # [1 2 3]
say @b;  # [[1 2 3]]

문제는 배열 할당 (변수에시길이있을 때 사용됨 @) 이 스칼라 컨테이너에있는 것처럼 %x<y> 단일 항목 으로 해석 한 다음 @b[0]. 당신은 모듈 자체를 제어 할 수는 없지만, 당신이 말한다면 당신은 내 예에 차이를 볼 수 있습니다 my %x is Map = …와 같은 Map스칼라 용기에 물건을 올려 놓지 않지만, Hash객체는 않습니다. Raku에게 단일 컨테이너가 아닌 단일 항목을 내용으로 처리하도록 지시하는 두 가지 방법이 있습니다.

  • 바인드 배열
    대신 사용은 @b = %x<y>, 당신이 사용 @b := %x<y>. @-sigiled 변수에 바인딩하면 자동으로 컨테이너가 해제됩니다.
  • zen 연산자 사용
    목록 / 해시 값이 하나로 취급되지 않도록하려면 zen 슬라이스를 사용하여 컨테이너가있는 경우 제거 할 수 있습니다. 이 작업을 수행 할 수 있습니다 중 하나를 할당에서 ( @b = %x<y>[]) 또는 상기 for루프 ( for @b[] -> $b). 그 주 <>, []그리고 {}효과적으로 동의어 관계없이 실제의 형태이다 - 대부분의 사람들은 이전과 일치 하나를 사용하십시오.

따라서 코드에서 다음을 수행 할 수 있습니다.

...
my %data = from-json($resp.content);

my @topics := %data<topic_list><topics>;   # (option 1) binding
my @topics  = %data<topic_list><topics><>; # (option 2) zen slice

for @topics -> $topic { say $topic<fancy_title>;
}

또는 옵션 3으로 루프에서

for @topics<> -> $topic { say $topic<fancy_title>;
}

.list나머지 답변 이후에 추측 할 수 있듯이 문제를 해결 하는 이유 는 컨테이너에없는 새로운 목록을 반환하기 때문입니다.