从 Raku HTTP 客户端请求中提取 JSON
Extracting JSON from a Raku HTTP client request
我无法理解这个 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>;
}
有谁知道失败的原因以及执行此任务的正确方法?
发生的事情是当你说
时你已经创建了一个数组的数组
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 变量会自动去容器化。
- 使用禅运算符
当您想避免 list/hash 值被视为一个值的可能性时,您可以使用 zen slice 删除恰好存在的任何容器。这可以在 赋值 (@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
解决问题的原因 — 正如您在回答其余部分后可能推测的那样 — 是 returns 一个不在容器中的新列表。
我无法理解这个 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>;
}
有谁知道失败的原因以及执行此任务的正确方法?
发生的事情是当你说
时你已经创建了一个数组的数组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 变量会自动去容器化。 - 使用禅运算符
当您想避免 list/hash 值被视为一个值的可能性时,您可以使用 zen slice 删除恰好存在的任何容器。这可以在 赋值 (@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
解决问题的原因 — 正如您在回答其余部分后可能推测的那样 — 是 returns 一个不在容器中的新列表。