我无法理解这个 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>;
}
Run Code Online (Sandbox Code Playgroud)
错误消息来自以下say $topic<fancy_title>行:
Type Array does not support associative indexing.
in block <unit> at http-clients/http.raku line 18
Run Code Online (Sandbox Code Playgroud)
我原以为$topic应该写为%topic,因为它是一个哈希数组,但这不起作用:
for @topics -> %topic {
say %topic<fancy_title>;
}
Run Code Online (Sandbox Code Playgroud)
错误消息是:
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
Run Code Online (Sandbox Code Playgroud)
如果您检查数据,它应该是一个散列,而不是一个数组。我试过@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>;
}
Run Code Online (Sandbox Code Playgroud)
有谁知道它为什么失败以及执行此任务的正确方法?
发生的事情是你创建了一个数组的数组,当你说
my @topics = %data<topic_list><topics>;
Run Code Online (Sandbox Code Playgroud)
这不是这些模块独有的,而是在 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]]
Run Code Online (Sandbox Code Playgroud)
问题在于数组赋值(当变量具有@sigil 时使用)将其解释%x<y> 为单个项目,因为它位于标量容器中,然后它很高兴地将其放入@b[0]. 虽然你无法控制模块本身,你可以看到其中的差别在我的例子,如果你说的my %x is Map = …是Map不要放置在容器标项目,但Hash对象一样。有两种方法可以告诉 Raku 将单个项目视为其内容,而不是单个容器。
@b = %x<y>,您使用@b := %x<y>. 绑定到@-sigiled 变量会自动解除容器化。@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>;
}
Run Code Online (Sandbox Code Playgroud)
或者在您的循环中,作为选项 3:
for @topics<> -> $topic {
say $topic<fancy_title>;
}
Run Code Online (Sandbox Code Playgroud)
.list修复问题的原因- 正如您在回答其余部分之后可能猜测的那样 - 是它返回一个不在容器中的新列表。
| 归档时间: |
|
| 查看次数: |
129 次 |
| 最近记录: |