Answers:
在Elixir / Erlang中没有直接的方法来获取变量的类型。
您通常想知道变量的类型以便采取相应的行动;您可以使用这些is_*
函数以便根据变量的类型执行操作。
向您学习一些Erlang有一章很好地介绍了在Erlang(以及Elixir)中的键入。
使用is_*
函数系列的最惯用的方法可能是在模式匹配中使用它们:
def my_fun(arg) when is_map(arg), do: ...
def my_fun(arg) when is_list(arg), do: ...
def my_fun(arg) when is_integer(arg), do: ...
# ...and so on
typeof(variable)
吗?
foo = [1, "hello", [1, 2, 3]]
用代码映射到,Enum.map(foo, fn(x) -> IO.puts x end)
因为[1,2,3]将被读取为字符(为什么erlang !!?),并且会显示很多笑脸(尝试一下!)。因此,即使仅在清单时才需要检查,我们还是被迫使用检查,否则大多数时候我们就不需要它。typeof使我们可以将if语句(O(n))转换为字典查找(O(1))。
Printable
协议,该协议可以包装和更改打印行为,例如整数列表。只要确保您不将其与Erlang代码一起使用-否则您将不知所措,想知道为什么看到的不是整数,而是消息的列表。
从elixir 1.2开始,i
iex中有一个命令,该命令将列出类型以及更多任何Elixir变量。
iex> foo = "a string"
iex> i foo
Term
"a string"
Data type
BitString
Byte size
8
Description
This is a string: a UTF-8 encoded binary. It's printed surrounded by
"double quotes" because all UTF-8 encoded codepoints in it are printable.
Raw representation
<<97, 32, 115, 116, 114, 105, 110, 103>>
Reference modules
String, :binary
如果查看该i
命令的代码,您将看到它是通过协议实现的。
https://github.com/elixir-lang/elixir/blob/master/lib/iex/lib/iex/info.ex
如果您想为Elixir中的任何数据类型实现一个功能,执行此操作的方法是为要使用该功能的所有数据类型定义一个协议和该协议的实现。不幸的是,您不能在警卫中使用协议功能。但是,简单的“类型”协议将非常容易实现。
undefined function i/1
-与信息/ 1相同
&i/1
是的功能IEx.Helpers
。如果将其&IEx.Helpers.i/1
放入香草Elixir中,CompileError
除非您已将其:iex
作为应用程序包含在内,否则将生成一个mix.exs
。
另一种方法是使用模式匹配。假设您正在使用使用%DateTime{}
结构的Timex,并且想查看一个元素是否为一个。您可以在方法中使用模式匹配找到匹配项。
def is_a_datetime?(%DateTime{}) do
true
end
def is_a_datetime?(_) do
false
end
switch
/来相应地采取行动case
。
我将其留在这里,是为了希望有人找出一个理智的版本。目前,在Google上对此没有好的答案。
defmodule Util do
def typeof(self) do
cond do
is_float(self) -> "float"
is_number(self) -> "number"
is_atom(self) -> "atom"
is_boolean(self) -> "boolean"
is_binary(self) -> "binary"
is_function(self) -> "function"
is_list(self) -> "list"
is_tuple(self) -> "tuple"
true -> "idunno"
end
end
end
为了完整性,测试用例:
cases = [
1.337,
1337,
:'1337',
true,
<<1, 3, 3, 7>>,
(fn(x) -> x end),
{1, 3, 3, 7}
]
Enum.each cases, fn(case) ->
IO.puts (inspect case) <> " is a " <> (Util.typeof case)
end
这是协议的解决方案;我不确定它们是否更快(我希望它们不会对所有类型进行循环),但是这非常丑陋(而且很脆弱;如果他们添加或删除基本类型或重命名,它将破坏它)。
defprotocol Typeable, do: def typeof(self)
defimpl Typeable, for: Atom, do: def typeof(_), do: "Atom"
defimpl Typeable, for: BitString, do: def typeof(_), do: "BitString"
defimpl Typeable, for: Float, do: def typeof(_), do: "Float"
defimpl Typeable, for: Function, do: def typeof(_), do: "Function"
defimpl Typeable, for: Integer, do: def typeof(_), do: "Integer"
defimpl Typeable, for: List, do: def typeof(_), do: "List"
defimpl Typeable, for: Map, do: def typeof(_), do: "Map"
defimpl Typeable, for: PID, do: def typeof(_), do: "PID"
defimpl Typeable, for: Port, do: def typeof(_), do: "Port"
defimpl Typeable, for: Reference, do: def typeof(_), do: "Reference"
defimpl Typeable, for: Tuple, do: def typeof(_), do: "Tuple"
IO.puts Typeable.typeof "Hi"
IO.puts Typeable.typeof :ok
我只是从https://elixirforum.com/t/just-created-a-typeof-module/2583/5中粘贴代码:)
defmodule Util do
types = ~w[function nil integer binary bitstring list map float atom tuple pid port reference]
for type <- types do
def typeof(x) when unquote(:"is_#{type}")(x), do: unquote(type)
end
end
只是因为没有人提到它
IO.inspect/1
输出以控制台对象...几乎等同于JSON.stringify
当您无法终生确定对象在测试中的外观时,这将非常有帮助。