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 comprobaciones de tipos en tiempo de compilación. Aun así, las especificaciones de tipo pueden ser útiles porque:

  • Sirven como documentación.
  • Pueden ser usadas por herramientas de análisis estático como Dialyzer para encontrar posibles bugs.

Se puede añadir una especificación de tipo 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 tipo:

  • 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 bajo 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 integrados, 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 argumentos

Los argumentos de la especificación de tipo también pueden nombrarse, lo que resulta ú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() frente a binary() frente a string()

String.t() es el tipo correcto para 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 a la hora de documentar funciones que trabajan con strings de Elixir.

En cambio, string() es un tipo distinto. Es un string de Erlang, conocido en Elixir como charlist. Conviene evitar el tipo string() en las especificaciones de tipo y 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 sencilla de usar Dialyzer en un proyecto de Elixir es con Dialyxir.

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

Aprende Especificaciones de tipos