如何在Elixir中正确扩展现有协议?
例如:00:00:00.000
返回" null"。
以Poison.encode!(:null)
协议为例。我想为Poison.Encoder
的议定书增加一个内容。但如果不重新定义本议定书中的所有内容,我不知道如何做到这一点。
Atom
嗨,我遇到了JSON编码的一个特殊问题,这引出了我的问题。
我希望所有defimpl Poison.Encoder, for: Atom do
alias Poison.Encoder
def encode(nil, _), do: "null"
def encode(true, _), do: "true"
def encode(false, _), do: "false"
# /------------------------------------------------------
# V My addition - What is the correct way of doing this?
def encode(:null, _), do: "null"
def encode(atom, options) do
Encoder.BitString.encode(Atom.to_string(atom), options)
end
end
原子在JSON中编码为:null
,而不是默认的null
(作为字符串)。我使用的JSON库是"null"
。
现在,上述工作,但它吐出警告,如:
Poison
答案 0 :(得分:2)
无法在Elixir中扩展现有协议。可能的解决方法是:
1。考虑使用类似%Null{}
而不是:null
atom的内容,并为此特定结构实施Poison.Encoder
(我无法使用{{3}为此目的):
defmodule Null do
# @derive [Poison.Encoder] # that won’t work
defstruct [json: "null"]
def encode(%Null{json: json}), do: json
end
defimpl Poison.Encoder, for: Null do
def encode(%Null{} = null), do: Null.encode(null)
end
2。在加载模块之前,有人可能会使用Erlang的@derive
和:code.delete/1
(不推荐)强制重新加载Poison.Encoder
来源{[1}} ]用:code.purge/1
加强整合:
:code.ensure_loaded(Poison.Encoder)
Protocol.assert_protocol!(Poison.Encoder)
:code.ensure_loaded(Poison.Encoder.Atom)
:code.delete(Poison.Encoder.Atom)
:code.purge(Poison.Encoder.Atom)
# your implementation
defimpl Poison.Encoder, for: Atom do
...
end
答案 1 :(得分:2)
重新实现内置类型的协议并不是一个好主意。您正在使用的其他软件包可能依赖于实现的原始行为。我将使用递归替换所有:null
值nil
的函数,然后将其传递给Poison.encode
。您可以创建一个包装函数来执行此转换,然后根据需要调用Poison.encode
。以下是此基本实现:
defmodule A do
def null_to_nil(:null), do: nil
def null_to_nil(list) when is_list(list) do
Enum.map(list, &null_to_nil/1)
end
def null_to_nil(map) when is_map(map) do
Enum.map(map, fn {k, v} -> {k, null_to_nil(v)} end) |> Map.new
end
def null_to_nil(term), do: term
end
IO.inspect A.null_to_nil([1, 2, :null, %{a: :null, b: %{b: [:null, :null]}}])
输出:
[1, 2, nil, %{a: nil, b: %{b: [nil, nil]}}]