在Elixir中,如何使用map变量初始化结构

bul*_*rog 69 elixir elixir-framework

我知道可以创建一个struct via %User{ email: 'blah@blah.com' }.但是,如果我有一个变量params = %{email: 'blah@blah.com'},有一种方法可以使用该变量创建该结构,例如,%User{ params }.

这给出了一个错误,只是想知道你是否可以爆炸它或其他方式?

Jos*_*lim 105

你应该使用这个struct/2功能.来自文档:

defmodule User do
  defstruct name: "john"
end

struct(User)
#=> %User{name: "john"}

opts = [name: "meg"]
user = struct(User, opts)
#=> %User{name: "meg"}

struct(user, unknown: "value")
#=> %User{name: "meg"}
Run Code Online (Sandbox Code Playgroud)

  • 如果您已强制执行密钥并希望确保它们存在于地图中,请使用`struct!/ 2`. (4认同)
  • 我糊涂了。该答案显示了关键字列表中结构的初始化。但是问题是从地图上询问结构。 (4认同)
  • 得到它了!struct / 2也可用于地图。因此,`opts =%{name:“ meg”}`起作用。 (2认同)

dot*_*aul 26

前面的答案都很好,但有一点需要注意:结构中的键是原子,哈希中的键可能是字符串.使用struct()方法只会复制匹配的键,并且字符串与原子不匹配.例:

defmodule User do
  defstruct name: "john"
end

opts = %{"name" => "meg"}
user = struct(User, opts)
#=> %User{name: "john"}
Run Code Online (Sandbox Code Playgroud)

使用merge也很奇怪,因为它将"撤消"Map的struct特性:

user = Map.merge(%User{}, opts)
#=> %{:__struct__ => User, :name => "john", "name" => "meg"}
Run Code Online (Sandbox Code Playgroud)

在Jose自己的elixir-lang-talk Google Group上找到了这个:

https://groups.google.com/d/msg/elixir-lang-talk/6geXOLUeIpI/L9einu4EEAAJ

除了你可以一次完成所有事情之外,这几乎是要走的路:

def to_struct(kind, attrs) do
  struct = struct(kind)
  Enum.reduce Map.to_list(struct), struct, fn {k, _}, acc ->
    case Map.fetch(attrs, Atom.to_string(k)) do
      {:ok, v} -> %{acc | k => v}
      :error -> acc
    end
  end
end
Run Code Online (Sandbox Code Playgroud)


She*_*yar 16

另一种方法是使用Map.merge/2:

合并(map1,map2)

例:

params
#=> %{email: "blah@blah.com"}

%User{} |> Map.merge(params)
#=> %User{ email: 'blah@blah.com' }
Run Code Online (Sandbox Code Playgroud)