你如何检查Elixir中的变量类型

时间:2015-02-07 00:34:40

标签: elixir

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

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

我在Elixir中读到类型检查器,例如&#39; is_bitstring&#39;,&#39; is_float&#39;,&#39; is_list&#39;,&#39; is_map&#39;等等,但如果您不知道该类型是什么呢?

8 个答案:

答案 0 :(得分:140)

从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中的任何数据类型实现函数,那么执行此操作的方法是为希望函数处理的所有数据类型定义协议和协议实现。不幸的是,你不能在守卫中使用协议功能。但是,简单的“类型”协议实现起来非常简单。

答案 1 :(得分:84)

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

您通常想知道变量的类型以便采取相应措施;您可以使用is_*函数,以便根据变量的类型进行操作。

了解你一些Erlang有a nice chapter关于输入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

答案 2 :(得分:21)

另外,出于调试目的,如果您不在iex中,可以直接调用它:

IEx.Info.info(5)
=> ["Data type": "Integer", "Reference modules": "Integer"]

答案 3 :(得分:20)

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

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

def is_a_datetime?(_) do
  false
end

答案 4 :(得分:12)

为了有人希望找出一个真正理智的版本,我会把它留在这里。目前谷歌上没有这个好消息的答案......

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"
            _                 -> "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

这是一个有协议的解决方案;我不确定它们是否更快(我当然希望它们不会对所有类型进行循环),但它非常难看(并且非常脆弱;如果它们添加或删除基本类型或重命名,它将会破坏它)。 / p>

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

答案 5 :(得分:10)

我只是粘贴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

答案 6 :(得分:2)

仅仅是因为没人提到它

IO.inspect/1

输出以控制对象......它几乎等同于JSON.stringify

非常有帮助,当你无法在生活中找出对象在测试中的样子时。

答案 7 :(得分:0)

我遇到的情况需要检查参数是否需要特定类型。也许可以活跃一个更好的方式。

像这样:

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

用法:

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