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


73

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

这会产生一个错误,只是想知道您是否可以将其爆炸或其他方式?

Answers:


113

您应该使用该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"}

4
如果您已强制使用密钥并希望确保它们在地图中存在,请struct!/2改用。
RusinaRange '17

4
我很困惑。该答案显示了关键字列表中结构的初始化。但是问题是从地图上询问结构。
艾哈迈德·费尔多斯

2
得到它了!struct/2也适用于地图。因此,opts = %{name: "meg"}作品。
艾哈迈德·费尔多斯

27

前面的答案都很好,但有一个警告:结构中的键是原子,哈希中的键可能是字符串。使用struct()方法将只复制匹配的键,而字符串将不匹配原子。例:

defmodule User do
  defstruct name: "john"
end

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

使用合并也是奇怪的,因为它将“撤消” Map的结构性质:

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

从Jose亲自在elixir-lang-talk Google网上论坛上找到了这个:

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

1
Jose的答案(以及您的演绎法)应该被接受,因为它来自Jose(在开玩笑)。使用merge给我带来了问题,是的,您完全失去了结构的本性。
sixFingers '16

感谢这一点,我需要一种非常通用的方法来初始化各种地图中的结构,这是我进行此操作
Owen,

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.