与嵌套 json 响应属性的模式匹配
pattern matching with nested json response attributes
我正在尝试找到一种更优雅的方法来在从 get_public_request
函数获得响应后设置变量。我在以下代码示例中引用 var1
和 var2
:
def get_prices(item) do
url = item_path(item)
response = get_public_request(url)
var1 = response["item"]["buy"]
var2 = response["item"]["sell"]
end
def get_public_request(url) do
HTTPoison.start
case HTTPoison.get(url) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
Poison.decode!(body)
...
end
end
我得到的响应(在 Poison.decocode 之后)如下所示:
%{"at" => 1536333060, "item" => %{"buy" => "8971.71", "area" => "A16", "sell" => "9019.89"}}
在您提供的代码中,您在 get_prices
中需要的一切都是这两个参数。选项是 return 他们明确来自 get_public_request
:
def get_public_request(url) do
HTTPoison.start
case HTTPoison.get(url) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
with %{"item" => %{"buy" => buy, "sell" => sell}} <- Poison.decode!(body),
do: {buy, sell}
...
end
end
Kernel.SpecialForms.with/1
将 return 任何未匹配的 RHO,因此如果我们进入 do
,我们就有了我们需要的东西。称其为:
def get_prices(item) do
url = item_path(item)
{var1, var2} = get_public_request(url)
end
如果您希望它们不总是出现在响应中,请使用 Kernel.SpecialForms.case/2
:
def get_public_request(url) do
HTTPoison.start
case HTTPoison.get(url) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
case Poison.decode!(body) do
%{"item" => %{"buy" => buy, "sell" => sell}} -> {buy, sell}
%{"item" => %{"buy" => buy}} -> {buy, nil}
%{"item" => %{"sell" => sell}} -> {nil, sell}
_ -> {nil, nil}
end
...
end
end
像@mudasobwa 一样,我会在 get_public_request
中进行数据提取,但使用其他两种语法之一:
地图上的模式匹配
def get_prices(item), do:
%{"buy":var1, "sell": var2} = item_path(item) |> get_public_request do
def get_public_request(url) do
HTTPoison.start
case HTTPoison.get(url) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
Poison.decode!(body)["item"] |> Map.take(["buy", "sell"])
...
end
end
注意:如果缺少 "buy" 或 "sell" 两个字段之一,此解决方案将在模式匹配期间崩溃。你可以避免使用 case
.
元组上的模式匹配
def get_prices(item), do: {var1, var2} = item_path(item) |> get_public_request
def get_public_request(url) do
HTTPoison.start
case HTTPoison.get(url) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
Poison.decode!(body)["item"] |> (&({&1["buy"],&1["sell"]}).()
...
end
end
如果要处理字段中是否有数据的情况,可以添加以下检查:
Poison.decode!(body)["item"] |> (&({Map.has_key?(&1,"buy") && &1["buy"] || nil, Map.has_key?(&1,"sell") && &1["sell"] || nil}).()
我正在尝试找到一种更优雅的方法来在从 get_public_request
函数获得响应后设置变量。我在以下代码示例中引用 var1
和 var2
:
def get_prices(item) do
url = item_path(item)
response = get_public_request(url)
var1 = response["item"]["buy"]
var2 = response["item"]["sell"]
end
def get_public_request(url) do
HTTPoison.start
case HTTPoison.get(url) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
Poison.decode!(body)
...
end
end
我得到的响应(在 Poison.decocode 之后)如下所示:
%{"at" => 1536333060, "item" => %{"buy" => "8971.71", "area" => "A16", "sell" => "9019.89"}}
在您提供的代码中,您在 get_prices
中需要的一切都是这两个参数。选项是 return 他们明确来自 get_public_request
:
def get_public_request(url) do
HTTPoison.start
case HTTPoison.get(url) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
with %{"item" => %{"buy" => buy, "sell" => sell}} <- Poison.decode!(body),
do: {buy, sell}
...
end
end
Kernel.SpecialForms.with/1
将 return 任何未匹配的 RHO,因此如果我们进入 do
,我们就有了我们需要的东西。称其为:
def get_prices(item) do
url = item_path(item)
{var1, var2} = get_public_request(url)
end
如果您希望它们不总是出现在响应中,请使用 Kernel.SpecialForms.case/2
:
def get_public_request(url) do
HTTPoison.start
case HTTPoison.get(url) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
case Poison.decode!(body) do
%{"item" => %{"buy" => buy, "sell" => sell}} -> {buy, sell}
%{"item" => %{"buy" => buy}} -> {buy, nil}
%{"item" => %{"sell" => sell}} -> {nil, sell}
_ -> {nil, nil}
end
...
end
end
像@mudasobwa 一样,我会在 get_public_request
中进行数据提取,但使用其他两种语法之一:
地图上的模式匹配
def get_prices(item), do:
%{"buy":var1, "sell": var2} = item_path(item) |> get_public_request do
def get_public_request(url) do
HTTPoison.start
case HTTPoison.get(url) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
Poison.decode!(body)["item"] |> Map.take(["buy", "sell"])
...
end
end
注意:如果缺少 "buy" 或 "sell" 两个字段之一,此解决方案将在模式匹配期间崩溃。你可以避免使用 case
.
元组上的模式匹配
def get_prices(item), do: {var1, var2} = item_path(item) |> get_public_request
def get_public_request(url) do
HTTPoison.start
case HTTPoison.get(url) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
Poison.decode!(body)["item"] |> (&({&1["buy"],&1["sell"]}).()
...
end
end
如果要处理字段中是否有数据的情况,可以添加以下检查:
Poison.decode!(body)["item"] |> (&({Map.has_key?(&1,"buy") && &1["buy"] || nil, Map.has_key?(&1,"sell") && &1["sell"] || nil}).()