箭头函数和冒号的映射方式(毒药 - JSON解码)

11
ab = %{a: 1}
ac = %{"a" => 1}

它们之间到底有什么区别?为什么Poison.decode!返回格式#2(我需要使用Ecto.Changeset.change中的格式#1)。

JSON响应来自API,看起来像:

[{"a":3}]
1个回答

17
ab = %{a: 1} # atom key you can access it like ab.a
ac = %{"a" => 1} # string key you can access it ac["a"]

Poison.decode!返回格式#2:

从应用程序外部获得的数据总体上来说是不可信的。考虑到原子分配可能导致长时间运行的 Erlang 系统出现内存耗尽,使用原子处理外部数据会为您的应用程序开启潜在的拒绝服务(DoS)攻击风险。

许多 Elixir 库都反映了这一事实,例如流行的 JSON 解析器Poison。良好的库通常在将外部数据转换为内部数据结构时使用字符串作为映射键。

如果您想将映射键从字符串转换为原子,可以执行以下操作:

iex> maps = %{"foo" => "bar"}
%{"foo" => "bar"}
iex> for {key, val} <- maps, into: %{}, do: {String.to_atom(key), val}
%{foo: "bar"}

4
使用String.to_existing_atom/1会更加安全一些。使用String.to_atom/1将会出现正好与本回答中提到的漏洞相同的问题。 - Martin Svalin
2
另外,通过原子键访问值,如示例中的 ab.a ,也可以使用 ab[:a]。方括号语法是更通用的访问语法,而点语法是在键为原子时适用于映射和结构的语法糖。 - Martin Svalin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接