繁体   English   中英

在 Elixir 中将地图转换为关键字列表

[英]Convert a map into a keyword list in Elixir

我有一张表格的地图:

%{"browser_name" => "Chrome", "platform" => "linux"}

我需要将其转换为关键字列表:

[browser_name: "Chrome", platform: "linux"]

实现这一目标的最佳方法是什么?

这不是行得通吗:

 def convert_to_klist(map) do
   Enum.map(map, fn({key, value}) -> {String.to_existing_atom(key), value} end)
 end

为了将来的读者,我会把它放在这里。

虽然人们肯定可能会在这里和那里盲目地调用String.to_atom/1 ,但强烈建议不要使用这种方法,因为它容易受到原子 DoS 攻击。

以下是 Erlang 文档的摘录:

原子不会被垃圾收集。 一旦一个原子被创建,它就永远不会被删除。 如果达到原子数的限制(默认为 1,048,576),模拟器将终止。

因此,在连续运行的系统中,将任意输入字符串转换为原子可能是危险的。 如果只允许某些明确定义的原子作为输入,则可以使用list_to_existing_atom/1来防范拒绝服务攻击。 (所有被允许的原子都必须在更早的时候创建,例如,通过在一个模块中简单地使用它们并加载该模块。)

http://erlang.org/doc/efficiency_guide/commoncaveats.html#list_to_atom-1

也就是说,无论您是从外部不受信任的来源接收映射(例如,它是对您的 API 的调用中的参数或其他东西),您都不能使用String.to_atom/1而应该使用String.to_existing_atom/1

否则,带有简单随机密钥生成器的入侵者会毫无问题地炸毁你的ErlangVM

您可以使用Keyword.new函数并传入一个转换函数作为第二个参数。

Keyword.new(%{"browser_name" => "Chrome", "platform" => "linux"}, fn {k,v} -> {String.to_existing_atom(k), v} end)
> [browser_name: "Chrome", platform: "linux"]

虽然这基本上等同于@NiteRain 接受的答案,但我认为它更明确一点,并向未来的代码读者展示了你的意图。

请参阅: https : //hexdocs.pm/elixir/Keyword.html#new/2

备查。 你也可以使用Enum.into/3

%{"browser_name" => "Chrome", "platform" => "linux"}
|> Enum.into([], fn {k, v} -> {String.to_existing_atom(k), v} end)

或在其较短的版本中:

%{"browser_name" => "Chrome", "platform" => "linux"}
|> Enum.into([], &{String.to_existing_atom(elem(&1,0)), elem(&1,1)})

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM