如何指定JSON解析的数据类型?

7

我有一个JSON响应,它是一个哈希数组:

[{"project" => {"id" => 1, "name" => "Internal"},
 {"project" => {"id" => 2, "name" => "External"}}]

我的代码看起来像这样:

client = HTTP::Client.new(url, ssl: true)
response = client.get("/projects", ssl: true)
projects = JSON.parse(response.body) as Array

这给了我一个数组,但似乎需要将元素强制转换才能使用它们,否则会出现undefined method '[]' for Nil (compile-time type is (Nil | String | Int64 | Float64 | Bool | Hash(String, JSON::Type) | Array(JSON::Type)))错误。
我尝试使用as Array(Hash),但是这会得到can't use Hash(K, V) as generic type argument yet, use a more specific type错误。
如何指定类型?
2个回答

10

你访问元素时必须将它们转换为相应类型:

projects = JSON.parse(json).as(Array)
project = projects.first.as(Hash)["project"].as(Hash)
id = project["id"].as(Int64)

http://carc.in/#/r/f3f

但对于这样结构良好的数据,最好使用JSON.mapping

class ProjectContainer
  JSON.mapping({
    project: Project
  })
end

class Project
  JSON.mapping({
    id: Int64,
    name: String
  })
end

projects = Array(ProjectContainer).from_json(json)
project = projects.first.project
pp id = project.id

http://carc.in/#/r/f3g 上可以查看此问题的稍微更详细的解释。在https://github.com/manastech/crystal/issues/982#issuecomment-121156428 中也提供了相关讨论。


1
你打败了我一分钟! - asterite
1
似乎 #as 语法已经改变了?https://play.crystal-lang.org/#/r/1uhw 或者你可以使用 to_i 和 to_s。 - rogerdpack
根据这个回答 https://dev59.com/Uq7la4cB1Zd3GeqPdXYM#52389618,JSON.mapping 将被移除,取而代之的是 JSON::Serializable。 - Guy C

3

您需要在每个步骤中继续进行投射:

projects = JSON.parse(response.body) as Array
projects.each do |project|
  project = project as Hash
  project = project["project"] as Hash
  id = project["id"] as Int
  name = project["name"] as String
end

但如果您的API响应具有已知结构,我强烈建议您使用JSON.mapping:https://crystal-lang.org/api/0.22.0/JSON.html#mapping-macro


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接