Elixir è un linguaggio a tipizzazione dinamica: non fornisce controlli di tipo a tempo di compilazione. Tuttavia, le specifiche di tipo possono comunque essere utili perché:
Una specifica di tipo può essere aggiunta a una funzione usando l'attributo di modulo @spec subito prima della definizione della funzione.
@spec longer_than?(String.t(), non_neg_integer()) :: boolean()
def longer_than?(string, length), do: String.length(string) > length
Espressioni consentite in una specifica di tipo:
Tipi di base, per esempio:
boolean()integer(), non_neg_integer(), pos_integer(), float()
list()map()any()Un'unione di tipi:
integer() | list(integer())
Tipi parametrizzati:
list(integer()), una lista di interi%{age: integer()}, una mappa con un valore intero sotto la chiave :age
Tipi remoti (definiti in qualche modulo), per esempio:
Letterali, per esempio:
%{}, una mappa vuota[], una lista vuota (ma [any()] è una lista non vuota):ok, un atomo letteraleTipi specializzati integrati, per esempio:
char(), un intero nell'intervallo 0..0x10FFFF
charlist(), una lista di caratterikeyword(), una lista di tuple di due elementi, dove il primo elemento è un atomoTipi personalizzati
Un elenco completo di tutti i tipi si trova nella sezione "Typespecs" della documentazione ufficiale.
Anche gli argomenti nella specifica di tipo possono avere un nome, il che è utile per distinguere più argomenti dello stesso tipo.
@spec to_hex({hue :: integer, saturation :: integer, lightness :: integer}) :: String.t()
I tipi personalizzati si possono definire usando uno dei tre attributi di modulo:
@type, definisce un tipo pubblico@typep, definisce un tipo privato@opaque, definisce un tipo pubblico la cui struttura è privata@type color :: {hue :: integer, saturation :: integer, lightness :: integer}
@spec to_hex(color()) :: String.t()
String.t() vs binary() vs string()
String.t() è il tipo corretto da usare per le stringhe di Elixir, che sono binari codificati in UTF-8. Tecnicamente, String.t() è definito come un binary(), e i due tipi sono equivalenti per gli strumenti di analisi, ma String.t() è la scelta che rivela meglio l'intenzione quando si documentano funzioni che lavorano con le stringhe di Elixir.
D'altra parte, string() è un tipo diverso. È una stringa di Erlang, nota in Elixir come charlist. Il tipo string() va evitato nelle specifiche di tipo; al suo posto va usato charlist().
Dialyzer è uno strumento di analisi statica che può individuare problemi come gli errori di tipo nel codice Erlang ed Elixir. Il modo più semplice per usare Dialyzer in un progetto Elixir è con Dialyxir.