如何检查长生不老药中的变量类型

在 Elixir 中,如何检查类型,比如在 Python 中:

>>> a = "test"
>>> type(a)
<type 'str'>
>>> b =10
>>> type(b)
<type 'int'>

我在 Elixir 中读到有类型检查器,比如‘ is _ bitstring’,‘ is _ float’,‘ is _ list’,‘ is _ map’等等,但是如果你不知道类型是什么呢?

100080 次浏览

在 Elixir/Erlang 中没有直接获取变量类型的方法。

您通常需要知道变量的类型,以便相应地执行操作; 您可以使用 is_*函数,以便根据变量的类型执行操作。

了解你一些二郎有关于在 Erlang 打字的 美好的一章(因此在长生不老药)。

使用 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

从 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命令的代码,您将看到这是通过一个 Protocol 实现的。

Https://github.com/elixir-lang/elixir/blob/master/lib/iex/lib/iex/info.ex

如果您希望在 Elixir 中为任何数据类型实现一个函数,那么实现该函数的方法是为您希望该函数处理的所有数据类型定义一个协议并实现该协议。不幸的是,你不能在警卫中使用协议功能。然而,一个简单的“类型”协议实现起来非常简单。

另一种方法是使用模式匹配。假设您正在使用 Timex,它使用 %DateTime{}结构,并且您想查看某个元素是否为1。你可以使用模式匹配在方法中找到一个匹配。

def datetime?(%DateTime{}) do
true
end


def datetime?(_) do
false
end

我把这个留在这里希望有人能想出一个真正正常的版本。目前在谷歌上还没有很好的答案。

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

为了完整起见,测试用例:

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

我只是粘贴来自 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(5)
=> ["Data type": "Integer", "Reference modules": "Integer"]

我遇到了一个情况需要检查的参数需要某种类型。也许可以激活一个更好的方式。

像这样:

@required [{"body", "binary"},{"fee", "integer"}, ...]
defp match_desire?({value, type}) do
apply(Kernel, :"is_#{type}", [value])
end

用法:

Enum.map(@required, &(match_desire?/1))

就因为没人提起过

IO.inspect/1

控制对象的输出... 其几乎等同于 JSON.stringify

当你一辈子都搞不清楚一个对象在测试中是什么样子的时候,这是非常有用的。

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返回的 tuple 进行模式匹配:

defmodule Type do
def of(x) do
[{_, type} | _] = IEx.Info.info(x)


type
end
end


Type.of(1) # "Integer"

使用 Elixir 协议的 Python 类型

模块实现的近似值是@Dimitry 应答 给你

协议源代码

这个代码对于一个答案来说很大,所以我创建了一个 github gist。

我是一个测试和长生不老药的菜鸟,所以任何改进都是值得赞赏的。

医生

可以在 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"