在Elixir中,我可以通过调用来检查变量是a map
还是a struct
,Kernel.is_map/1
因为Structs是下面的Maps,但是我想区分这两者.我知道我可以调用__struct__
Struct来获取它的模块名称,但是在普通地图上调用它会抛出:
** (KeyError) key :__struct__ not found in: %{}
Run Code Online (Sandbox Code Playgroud)
所以我的问题是,如何检查变量是地图还是结构?
用例示例:
# I want to handle struct and map inputs differently in my Module
defmodule DifferentThings do
def do_something(arg) when is_map(arg) do
# Do something with Maps
end
def do_something(arg) when is_struct(arg) do
# But handle Structs differently
# Issue is, `is_struct` does not exist
end
end
Run Code Online (Sandbox Code Playgroud)
Ale*_*nts 24
通常检查map是否是结构:
Map.has_key?(struct, :__struct__)
Run Code Online (Sandbox Code Playgroud)
对于不同的方法声明(更一般的方法是第二):
defmodule DifferentThings do
def do_something(%{__struct__: _} = arg) do
# ...
end
def do_something(arg) when is_map(arg) do
# ...
end
end
Run Code Online (Sandbox Code Playgroud)
可以在struct和map之间进行模式匹配,如下所示
defmodule DifferentThings do
def do_something(arg = %_x{}) do
IO.puts "This is a struct"
end
def do_something(arg = %{}) do
IO.puts "This is a map"
end
end
Run Code Online (Sandbox Code Playgroud)
您不能为 Map 与 Struct 使用保护设置单独的函数头,但您可以使用模式匹配来实现。
defmodule Guard do
def foo(%{:__struct__ => x }) do
Struct
end
def foo(x) when is_map x do
Map
end
end
Run Code Online (Sandbox Code Playgroud)
检查某个术语是否为 a 的最简单方法map
是使用:
Map.has_key?(map, :__struct__)
Run Code Online (Sandbox Code Playgroud)
它在守卫中不起作用,因此我们必须事先诉诸于模式匹配:__struct__
函数子句中的键:
def some_fun(%__struct__: _module}), do: ...
Run Code Online (Sandbox Code Playgroud)
但这看起来很脏。
is_struct/1
从 Erlang/OTP 21 开始,引入了一些新的守卫,我们可以用它们来定义我们自己的守卫:
defguard is_struct(term) when is_map(term) and :erlang.is_map_key(:__struct__, term)
defguard is_struct(term, module) when is_struct(term) and :erlang.map_get(:__struct__, term) == module
Run Code Online (Sandbox Code Playgroud)
现在您可以将它们用作函数防护:
def do_something(account) when is_struct(account, User) do
# Do something with %User{} structs
end
def do_something(struct) when is_struct(struct) do
# Do something with random structs
end
def do_something(map) when is_map(map) do
# Do something with maps
end
Run Code Online (Sandbox Code Playgroud)
注意:这些很快就会添加到 Elixir 标准库本身中。请关注此ElixirForum 主题中的讨论。
归档时间: |
|
查看次数: |
3998 次 |
最近记录: |