Las estructuras en Elixir, conocidas como structs, son una forma de darle forma y semántica a los mapas, limitando las claves que pueden contener y facilitando su manejo. A diferencia de los mapas ordinarios, que pueden tener cualquier clave, los structs nos permiten definir un conjunto fijo de campos, lo que ayuda a evitar errores y a expresar mejor la intención de nuestros datos.
Para crear un struct, debemos definirlo dentro de un módulo usando la palabra clave defstruct. Por ejemplo, si queremos representar un perfil con campos como nombre, país, bebida, comida y animal, lo haríamos así:
defmodule Perfil do
defstruct [:nombre, :país, :bebida, :comida, :animal]
end
Al crear una instancia de este struct, usamos la sintaxis %Perfil{}. Si lo creamos vacío, el struct tendrá todas las claves definidas con valor nil por defecto:
perfil = %Perfil{}
# %Perfil{nombre: nil, país: nil, bebida: nil, comida: nil, animal: nil}
Aunque los structs son mapas bajo el capó, tienen una clave oculta que indica su tipo, lo que permite que Elixir los distinga de mapas normales. Esto significa que podemos acceder a sus campos con la sintaxis de acceso a mapas, como perfil.animal o perfil[:bebida].
Sin embargo, a diferencia de los mapas, los structs no permiten añadir claves arbitrarias. Si intentamos agregar una clave que no está definida en el struct, como :hola, el resultado dejará de ser un struct válido y se convertirá en un mapa común, perdiendo la semántica que habíamos definido. Por ejemplo:
perfil = %Perfil{}
perfil_modificado = Map.put(perfil, :hola, "adiós")
# perfil_modificado ya no es un struct Perfil válido
Esto nos ayuda a mantener la integridad de nuestros datos y a evitar que se introduzcan claves inesperadas.
También podemos asignar valores por defecto a los campos del struct al definirlo. Para ello, en lugar de pasar solo una lista de átomos, pasamos una lista de pares clave-valor, como una keyword list:
defmodule Perfil do
defstruct nombre: nil, país: nil, bebida: nil, comida: "papayons", animal: nil
end
Con esta definición, si no especificamos un valor para comida al crear el struct, automáticamente tendrá el valor "papayons".
Los structs permiten hacer pattern matching, tanto entre structs del mismo tipo como con mapas ordinarios, siempre que las claves coincidan. Sin embargo, no podemos hacer pattern matching directamente entre un mapa y un struct sin tener en cuenta la clave oculta que identifica el struct.
Un uso muy común de los structs en Elixir es en librerías como Ecto, que es un ORM para bases de datos. Ecto utiliza structs para representar filas de tablas, lo que permite definir claramente los campos que esperamos en cada registro y facilita la conversión entre datos de la base y estructuras en Elixir.
En definitiva, los structs son una herramienta sencilla pero poderosa para dar forma y significado a nuestros datos en Elixir, ayudándonos a evitar errores y a trabajar con información más estructurada y clara.