【发布时间】:2021-12-07 03:40:35
【问题描述】:
我有一张表格的地图:
%{"browser_name" => "Chrome", "platform" => "linux"}
我需要将其转换为关键字列表:
[browser_name: "Chrome", platform: "linux"]
实现这一目标的最佳方法是什么?
【问题讨论】:
标签: elixir
我有一张表格的地图:
%{"browser_name" => "Chrome", "platform" => "linux"}
我需要将其转换为关键字列表:
[browser_name: "Chrome", platform: "linux"]
实现这一目标的最佳方法是什么?
【问题讨论】:
标签: elixir
这不可行吗:
def convert_to_klist(map) do
Enum.map(map, fn({key, value}) -> {String.to_existing_atom(key), value} end)
end
【讨论】:
String.to_atom/1容易受到atom DoS攻击。
String.to_existing_atom/1
为了以后的读者,我会把它放在这里。
虽然人们肯定会在这里和那里盲目地调用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,而应使用@987654324 @ 代替。
否则,带有简单随机密钥生成器的入侵者会毫无问题地炸毁您的 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 接受的答案,但我认为它更明确一些,并向您的代码的未来读者展示了您的意图。
【讨论】:
供日后参考。你也可以使用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)})
【讨论】: