tutorial - ¿Cómo se verifica el tipo de variable en Elixir?
elixir también se buscó (8)
Acabo de pegar el código de 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
En Elixir, ¿cómo verifica el tipo, como en Python:
>>> a = "test"
>>> type(a)
<type ''str''>
>>> b =10
>>> type(b)
<type ''int''>
Leí en Elixir que hay verificadores de tipo como ''is_bitstring'', ''is_float'', ''is_list'', ''is_map'', etc., pero ¿qué pasa si no tiene idea de cuál podría ser el tipo?
Comenzando en elixir 1.2 hay un comando
i
en iex que enumerará el tipo y más de cualquier variable de 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
Si busca en el código el comando
i
, verá que esto se implementa a través de un protocolo.
https://github.com/elixir-lang/elixir/blob/master/lib/iex/lib/iex/info.ex
Si desea implementar una función para cualquier tipo de Datos en Elixir, la forma de hacerlo es definir un Protocolo e implementar el Protocolo para todos los tipos de datos en los que desea que funcione la función. Desafortunadamente, no puedes usar una función de Protocolo en guardias. Sin embargo, un simple protocolo de "tipo" sería muy sencillo de implementar.
Me encontré con una situación en la que es necesario verificar que el parámetro debe ser cierto tipo. Quizás pueda activarse de una mejor manera.
Me gusta esto:
@required [{"body", "binary"},{"fee", "integer"}, ...]
defp match_desire?({value, type}) do
apply(Kernel, :"is_#{type}", [value])
end
Uso:
Enum.map(@required, &(match_desire?/1))
No hay forma directa de obtener el tipo de variable en Elixir / Erlang.
Por lo general, desea saber el tipo de una variable para actuar en consecuencia;
puede usar las funciones
is_*
para actuar según el tipo de una variable.
Learn You Some Erlang tiene un buen capítulo sobre escribir en Erlang (y, por lo tanto, en Elixir).
La forma más idiomática de usar la familia de funciones
is_*
probablemente sería usarlas en coincidencias de patrones:
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
Otro enfoque es utilizar la coincidencia de patrones.
Digamos que está utilizando Timex, que utiliza una estructura
%DateTime{}
, y desea ver si un elemento es uno.
Puede encontrar una coincidencia utilizando la coincidencia de patrones en el método.
def is_a_datetime?(%DateTime{}) do
true
end
def is_a_datetime?(_) do
false
end
Solo dejaré esto aquí por el bien de alguien que, con suerte, descubra una versión realmente sensata. Por el momento no hay buenas respuestas para esto en 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"
_ -> "idunno"
end
end
end
En aras de la integridad, los casos de prueba:
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
Aquí hay una solución con protocolos; No estoy seguro de si son más rápidos (seguramente espero que no estén haciendo un bucle sobre todos los tipos), pero es bastante feo (y frágil; si agregan o eliminan un tipo básico o cambian el nombre, lo romperá).
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
Solo porque nadie lo ha mencionado
IO.inspect/1
Salidas para consolar el objeto ... es casi equivalente a JSON.stringify
Muy útil cuando simplemente no puede durante toda su vida descubrir cómo se ve un objeto en una prueba.
También para fines de depuración, si no está en iex, puede llamarlo directamente:
IEx.Info.info(5)
=> ["Data type": "Integer", "Reference modules": "Integer"]