Elixir如何将Map结构转换为Record结构

jsv*_*isa 7 elixir

我有一个Record结构和一个Map结构,如:

defmodule Foo.Bar do
  defstruct boo: nil, baz: nil
end

defmodule Foo do
  require Record
  Record.defrecord :bar, Foo.Bar, [boo: nil, baz: nil]
end
Run Code Online (Sandbox Code Playgroud)

我可以像这样将Record转换为Map:

defp update_map({k, v}, map), do: Map.update!(map, k, fn(_) -> v end)
defp rd2map(rd) do
  Foo.bar(rd) |> Enum.reduce(%Foo.Bar{}, &update_map/2)
end
Run Code Online (Sandbox Code Playgroud)

但是如何将地图转换为记录呢?

Pat*_*ity 14

Elixir Records已被弃用.Record现在存在于Elixir中的模块仅用于两件事:

  1. 使用简短的内部数据
  2. 与Erlang记录接口

这意味着除非您尝试从Erlang文件中提取记录信息,否则您可能不应该使用它们.

关于你原来的问题,这里是我如何来回转换Erlang Records和Elixir Structs.一旦你意识到一个结构只是一个Map包含__struct__: Foo.Bar,并且一个Record只是一个以{Foo.Bar, ...}它开头的元组非常简单.唯一棘手的一点是有关记录字段的信息仅在编译时可用.因此,默认情况下没有动态构建记录的方法.据我所知,你只能通过在某处存储字段定义来解决这个问题,并使用它来生成结构和记录定义.稍后,重新使用相同的源来构建具有默认值(即记录)的有序元组.记住,你真的不应该使用记录.因此,请注意:前方丑陋的黑客;-)

defmodule Foo.Bar do
  @fields [boo: nil, baz: nil]
  def fields, do: @fields
  defstruct @fields
end

defmodule Foo do
  require Record
  Record.defrecord :bar, Foo.Bar, Foo.Bar.fields
end

defmodule Foo.Utils do
  require Foo

  def record_to_struct(record) do
    [{:__struct__, Foo.Bar} | Foo.bar(record)] |> Enum.into(%{})
  end

  def struct_to_record(struct) do
    map = Map.from_struct(struct)
    for {key, default} <- Foo.Bar.fields, into: [Foo.Bar] do
      Dict.get(map, key, default)
    end |> List.to_tuple
  end
end
Run Code Online (Sandbox Code Playgroud)