是否有更惯用的方式将json转换为Crystal中的特定哈希类型?

问题描述

我有一个JSON::Any,当我访问“ params”键时,我得到了一个JSON::Any表示以下内容:

{"a":0.9029593355545088,"b":2,"lh":1000,"ph":10,"pl":1}

我想将其转换为Hash(String,Float64),而我发现最简单的方法是使用to_json,然后使用from_json,因为Hash#from_json不这样做。不能接受JSON::Any类型。

params = Hash(String,Float64).from_json(json["params"].to_json)

似乎我在某个地方缺少概念或习语。有更好的方法吗?


PS

如果您想玩这个,下面是一个片段:

require "json"
json_string = %({"params": {"a": 1.2,"b": 2}})
json = JSON.parse(json_string)
Hash(String,Float64).from_json(json["params"].to_json)

请注意,在我的代码中,我无法轻松访问json_string。因为它埋在了更大的json响应中,所以我必须对其进行解析才能解析到该位置,一旦解析,我就会得到一个JSON::Any。因此,在使用from_json将其转换为哈希之前,似乎需要将其转换为json字符串。

解决方法

JSON.parse返回一个JSON::Any,因此您可以使用其方便的投射帮助器:

json["params"].as_h.transform_values(&.raw.as(Float64|Int64).to_f)

但是,如果结构定义明确,最好使用JSON::Serializable

record ApiResponse,params : Hash(String,Float64) do
  include JSON::Serializable
end

json_string = %({"params": {"a": 1.2,"b": 2}})
json = ApiResponse.from_json(json_string)
json.params # => {"a" => 1.2,"b" => 2.0}

甚至更好:

record ApiResponse,params : ApiParams do
  include JSON::Serializable
end

record ApiParams,a : Float64,b : Float64 do
  include JSON::Serializable
end

json_string = %({"params": {"a": 1.2,"b": 2}})
json = ApiResponse.from_json(json_string)
json.params # => ApiParams(@a=1.2,@b=2.0)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...