json 在 elixir 中序列化时的浮点格式

Float format when json serializing in elixir

Elixir 默认对大于 1000 的浮点数使用科学记数法。这会在 json 序列化过程中产生不良副作用。

iex(5)> val = 1000.00
1.0e3
iex(11)> Poison.encode(val)
{:ok, "1.0e3"}

我想要的输出是

iex(11)> Poison.encode(val)
{:ok, "1000.00"}

我看到 使用 :erlang.float_to_binary(0.005 * 2.7 / 100, [:compact, {:decimals, 10}]):io.format("~f~n",[0.005 * 2.7 / 100]),但这需要修补 Poison 或在编码前手动检查所有数据。

在 elixir 中是否有更简洁的方法强制默认 flot 为二进制格式?

Poison 允许实现 Poison.Encoder protocol. The implementation for Float obviously exists,这就是为什么我建议将您的浮点数预先包装到自定义 FloatStruct 中:

defmodule FloatStruct do
  defstruct value: 0.0, format: [:compact, {:decimals, 10}]
end

defimpl Poison.Encoder, for: FloatStruct do
  def encode(%{value: value, format: format}, options) do
    Poison.Encoder.BitString.encode(
      :erlang.float_to_binary(value, format), options)
  end
end

我知道这需要遍历嵌套的术语来用 FloatStruct 包装 Float,但我没有看到任何更简单的方法。不过我可能是错的。


有人可能会免费支持 OP 格式中提到的两种格式:

defimpl Poison.Encoder, for: FloatStruct do
  def encode(%{value: value, format: format}, options) do
    Poison.Encoder.BitString.encode(
      format(value, format), options)
  end

  defp format(value, format) when is_list(format),
    do: :erlang.float_to_binary(value, format)
  defp format(value, format) when is_binary(format),
    do: :io.format(format, [value])
end