>>> a = "test"
>>> type(a)
<type 'str'>
>>> b =10
>>> type(b)
<type 'int'>
我在 Elixir 中读到有诸如 'is_bitstring'、'is_float'、'is_list'、'is_map' 等类型检查器,但如果你不知道类型是什么怎么办?
>>> a = "test"
>>> type(a)
<type 'str'>
>>> b =10
>>> type(b)
<type 'int'>
我在 Elixir 中读到有诸如 'is_bitstring'、'is_float'、'is_list'、'is_map' 等类型检查器,但如果你不知道类型是什么怎么办?
从Elixir 1.2开始,在iex中有一个i
命令,可以列出任何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中为任何数据类型实现函数,那么要做的方法就是定义一个协议,并针对您希望该函数适用于的所有数据类型实现该协议。不幸的是,您无法在Guard中使用Protocol函数。然而,一个简单的“类型”协议非常容易实现。
is_*
函数根据变量类型执行操作。Learn You Some 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)
的结果吗? - whatyouhideEnum.map(foo, fn(x) -> IO.puts x end)
无法映射到 foo = [1, "hello", [1, 2, 3]]
,因为 [1,2,3] 会被解释为字符(为什么Erlang!!?),并显示一堆笑脸(试试看!)。所以,即使不需要 inspect,我们也被迫使用它,除非它是一个列表,否则大多数情况下我们不需要它。typeof 让我们将 O(n) 的 if 语句转换为 O(1) 的字典查找。 - Dmytro另外,为了调试目的,如果您不在iex中,可以直接调用它:
IEx.Info.info(5)
=> ["Data type": "Integer", "Reference modules": "Integer"]
i/1
不同,因为i/1
仅打印信息,但是这个函数让你可以捕获结果。 - zenw0lf我只是为了希望有人能够找到一个实际理智的版本,就把这个留在这里。目前在谷歌上还没有好的答案...
defmodule Util do
def typeof(a) do
cond do
is_float(a) -> "float"
is_number(a) -> "number"
is_atom(a) -> "atom"
is_boolean(a) -> "boolean"
is_binary(a) -> "binary"
is_function(a) -> "function"
is_list(a) -> "list"
is_tuple(a) -> "tuple"
true -> "idunno"
end
end
end
为了完整性起见,测试用例: For the sake of completeness, test cases:
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(a)
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
self
是当前进程的 PID
,这可能会让人感到困惑。 - mrroot5self
不是一个关键字,您指的是允许被本地变量/参数命名为self
的self/1
,而且没有任何合法问题可以被遮蔽。话虽如此,我将self
更改为a
,我想在最终版本中用_
替换a
,但我不记得Elixir足够了解是否正确(尽管它似乎可以工作)。 - Dmytro另一种方法是使用模式匹配。比如你正在使用Timex,它使用一个%DateTime{}
结构体,并且你想查看一个元素是否是其中之一。你可以在该方法中使用模式匹配来查找匹配项。
def datetime?(%DateTime{}) do
true
end
def datetime?(_) do
false
end
switch
/case
语句。 - mariotomo我只是从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
在iex和您的代码中,您可以使用IEx.Info.info
。结果是一个元组列表,因此包含为字符串的实际类型信息需要进行一些解包:
IEx示例
iex(1)> "abc" |> IEx.Info.info |> hd |> elem(1)
"BitString"
在你的代码中
def datatype(myvar) do
myvar |> IEx.Info.info |> hd |> elem(1)
end
var1 = {1,2,3}
IO.puts(datatype(var1)) # will print the string "Tuple"
Useful.typeof/1
受这个主题的启发,我们将 typeof/1
添加到了我们的Useful
函数库中。它正是你所期望的。
在mix.exs
文件中将其添加到你的deps
中:
def deps do
[
{:useful, "~> 0.4.0"}
]
end
用法:
iex> pi = 3.14159
iex> Useful.typeof(pi)
"float"
iex> fun = fn (a, b) -> a + b end
iex> Useful.typeof(fun)
"function"
iex> Useful.typeof(&Useful.typeof/1)
"function"
iex> int = 42
iex> Useful.typeof(int)
"integer"
iex> list = [1,2,3,4]
iex> Useful.typeof(list)
"list"
文档: https://hexdocs.pm/useful/Useful.html#typeof/1
一如既往,欢迎反馈、贡献和改进。
根据这里的实现 (链接),您可以对 IEx.Info.info/1
返回的元组进行模式匹配:
defmodule Type do
def of(x) do
[{_, type} | _] = IEx.Info.info(x)
type
end
end
Type.of(1) # "Integer"
@required [{"body", "binary"},{"fee", "integer"}, ...]
defp match_desire?({value, type}) do
apply(Kernel, :"is_#{type}", [value])
end
使用方法:
Enum.map(@required, &(match_desire?/1))
&i/1
是IEx.Helpers
中的一个函数。如果你在原始的 Elixir 中输入&IEx.Helpers.i/1
,除非你已经将:iex
应用程序包含在你的mix.exs
文件中,否则会生成一个CompileError
。 - popedotninja