Elixir - JasonHelpers - 如何将关键字列表发送到 json_map?

Châ*_*ĩnh 1 json dictionary elixir

我有一个数据结构,我想将其转换为 json 并保留键顺序。

例如: %{ x: 1, a: 5}应转换为"{\"x\": 1, \"a\": 5}"

毒药做到这一点没有任何问题。但是当我升级到 Jason 时,它变成了"{\"a\": 5, \"x\": 1}".

所以我使用 JasonHelpers json_map 来保留这样的顺序:

Jason.Helpers.json_map([x: 1, a: 5])
Run Code Online (Sandbox Code Playgroud)

它创建一个具有正确顺序的片段。

但是,当我使用变量来执行此操作时:

list = [x: 1, a: 5]
Jason.Helpers.json_map(list)
Run Code Online (Sandbox Code Playgroud)

我有一个错误:

** (Protocol.UndefinedError) protocol Enumerable not implemented for {:list, [line: 15], nil} of type Tuple.
....
Run Code Online (Sandbox Code Playgroud)

问题:如何将预先计算的列表传递到Jason.Helpers.json_map

计算很复杂,所以我不想仅仅为了使用json_map而重复代码,而是使用返回列表的函数。

Ada*_*hip 5

json_map/1是一个宏,来自它的文档:

从编译时关键字对 JSON 映射进行编码。

它设计用于在编译时编译 JSON,这就是它不适用于运行时变量的原因。

一年前,Jason 库添加了对关键字列表编码的支持,但看起来还没有推送到十六进制。我设法通过从 github 获取最新代码来使其工作:

defp deps do
  [{:jason, git: "https://github.com/michalmuskala/jason.git"}]
end
Run Code Online (Sandbox Code Playgroud)

然后通过创建一个实现的结构Jason.Encoder(改编自Jason 作者的此解决方案):

defmodule OrderedObject do
  defstruct [:value]

  def new(value), do: %__MODULE__{value: value}

  defimpl Jason.Encoder do
    def encode(%{value: value}, opts) do
      Jason.Encode.keyword(value, opts)
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

现在我们可以使用有序键对对象进行编码:

iex(1)> Jason.encode!(OrderedObject.new([x: 1, a: 5]))
"{\"x\":1,\"a\":5}"
Run Code Online (Sandbox Code Playgroud)