Tracks
/
Elixir
Elixir
/
Temario
/
Especificaciones de tipos
Es

Especificaciones de tipos en Elixir

1 ejercicio

Acerca de Especificaciones de tipos

Elixir es un lenguaje de tipado dinámico, lo que significa que no proporciona verificaciones de tipos en tiempo de compilación. Aun así, las especificaciones de tipos pueden ser útiles porque:

  • Sirven como documentación.
  • Herramientas de análisis estático como Dialyzer pueden usarlas para encontrar posibles bugs.

Se puede agregar una especificación de tipos a una función usando el atributo de módulo @spec justo antes de la definición de la función.

@spec longer_than?(String.t(), non_neg_integer()) :: boolean()
def longer_than?(string, length), do: String.length(string) > length

Tipos

Expresiones permitidas en una especificación de tipos:

  • Tipos básicos, por ejemplo:

    • boolean()
    • integer(), non_neg_integer(), pos_integer(), float()
    • list()
    • map()
    • any()
  • Una unión de tipos:

    • p. ej. integer() | list(integer())
  • Tipos parametrizados:

    • p. ej. list(integer()): una lista de enteros
    • p. ej. %{age: integer()}: un mapa con un valor entero en la clave :age
  • Tipos remotos (definidos en algún módulo), por ejemplo:

  • Literales, por ejemplo:

    • %{}: un mapa vacío
    • []: una lista vacía (pero [any()] es una lista no vacía)
    • p. ej. :ok: un literal de átomo
  • Tipos especializados incorporados, por ejemplo:

    • char(): un entero del rango 0..0x10FFFF
    • charlist(): una lista de caracteres
    • keyword(): una lista de tuplas de dos elementos, donde el primer elemento es un átomo
  • Tipos personalizados

Puedes encontrar una lista completa de todos los tipos en la sección «Typespecs» de la documentación oficial.

Nombrar los argumentos

Los argumentos en la especificación de tipos también se pueden nombrar, lo cual es útil para distinguir varios argumentos del mismo tipo.

@spec to_hex({hue :: integer, saturation :: integer, lightness :: integer}) :: String.t()

Tipos personalizados

Los tipos personalizados se pueden definir usando uno de estos tres atributos de módulo:

  • @type: define un tipo público
  • @typep: define un tipo privado
  • @opaque: define un tipo público cuya estructura es privada
@type color :: {hue :: integer, saturation :: integer, lightness :: integer}

@spec to_hex(color()) :: String.t()

String.t() vs binary() vs string()

String.t() es el tipo correcto para usar con los strings de Elixir, que son binarios codificados en UTF-8. Técnicamente, String.t() se define como un binary(), y esos dos tipos son equivalentes para las herramientas de análisis, pero String.t() es la opción que revela mejor la intención al documentar funciones que trabajan con strings de Elixir.

Por otro lado, string() es un tipo diferente. Es un string de Erlang, conocido en Elixir como charlist. El tipo string() se debe evitar en las especificaciones de tipos y se debe usar charlist() en su lugar.

Dialyzer

Dialyzer es una herramienta de análisis estático que puede detectar problemas como errores de tipos en código Erlang y Elixir. La forma más fácil de usar Dialyzer en un proyecto de Elixir es con Dialyxir.

Editar en GitHub El enlace se abre en una ventana o pestaña nueva

Aprende Especificaciones de tipos