Los structs son una extensión construida sobre los mapas, que proporcionan verificaciones en tiempo de compilación y valores predeterminados. Un struct recibe el nombre del módulo en el que se define. Para definir un struct, usa la construcción defstruct. Por lo general, la construcción va inmediatamente después de la definición del módulo. defstruct acepta una lista de átomos (para valores predeterminados nil) o una lista de palabras clave (para valores predeterminados especificados). Los campos sin valores predeterminados deben ir antes que los campos con valores predeterminados.
defmodule Plane do
defstruct [:engine, wings: 2]
end
plane = %Plane{}
# => %Plane{engine: nil, wings: 2}
Como los structs se construyen sobre mapas, podemos usar la mayoría de las funciones de mapas para obtener y manipular valores. El Access Behaviour no está implementado para los structs. En su lugar, se recomienda usar el operador de acceso estático . para acceder a los campos del struct.
obtener/consultar los valores de los campos:
plane = %Plane{}
plane.engine
# => nil
Map.fetch(plane, :wings)
# => {:ok, 2}
actualizar los valores de los campos
plane = %Plane{}
%{plane | wings: 4}
# => %Plane{engine: nil, wings: 4}
Los structs se pueden usar en la coincidencia de patrones con o sin el nombre del struct.
plane = %Plane{}
%Plane{wings: wings} = plane
%{wings: wings} = plane
Al incluir el nombre del struct en el patrón, puedes asegurarte de que tanto el lado izquierdo como el derecho sean structs del mismo tipo.
defmodule Helicopter do
defstruct [:engine, rotors: 1]
end
%Plane{} = %Helicopter{}
# => (MatchError) no match of right hand side value: %Helicopter{engine: nil, rotors: 1}
Podemos usar el atributo de módulo @enforce_keys con una lista de las claves de los campos para asegurarnos de que los valores se inicialicen cuando se crea el struct. Si una clave no está en la lista, su valor será nil, como se vio en el ejemplo anterior. Si una clave exigida no se inicializa, se produce un error.
defmodule User do
@enforce_keys [:username]
defstruct [:username]
end
%User{}
# => (ArgumentError) the following keys must also be given when building struct User: [:username]
En este ejercicio vas a jugar con un auto a control remoto, para el que por fin ahorraste suficiente dinero para comprarlo.
Los autos empiezan con la batería llena (100%). Cada vez que conduces el auto con el control remoto, recorre 20 metros y consume uno por ciento de la batería. El apodo del auto no se conoce hasta que se crea.
El auto a control remoto tiene una elegante pantalla LED que muestra dos datos:
"<METERS> meters"."Battery at <PERCENTAGE>%".Si la batería está al 0%, ya no puedes conducir el auto y la pantalla de la batería mostrará "Battery empty".
Implementa la función RemoteControlCar.new/0 para que devuelva un struct de auto a control remoto totalmente nuevo:
RemoteControlCar.new()
# => %RemoteControlCar{
# battery_percentage: 100,
# distance_driven_in_meters: 0,
# nickname: "none"
# }
El struct requiere el apodo; asegúrate de inicializar un valor en la función new, pero no en el struct.
Implementa la función RemoteControlCar.new/1 para que devuelva un struct de auto a control remoto totalmente nuevo con un apodo proporcionado:
RemoteControlCar.new("Blue")
# => %RemoteControlCar{
# battery_percentage: 100,
# distance_driven_in_meters: 0,
# nickname: "Blue"
# }
Implementa la función RemoteControlCar.display_distance/1 para que devuelva la distancia tal como se muestra en la pantalla LED:
car = RemoteControlCar.new()
RemoteControlCar.display_distance(car)
# => "0 meters"
Asegúrate de que la función solo acepte un struct RemoteControlCar como argumento.
Implementa la función RemoteControlCar.display_battery/1 para que devuelva el porcentaje de batería tal como se muestra en la pantalla LED:
car = RemoteControlCar.new()
RemoteControlCar.display_battery(car)
# => "Battery at 100%"
Asegúrate de que la función solo acepte un struct RemoteControlCar como argumento. Si la batería está al 0%, la pantalla de la batería mostrará "Battery empty".
Implementa la función RemoteControlCar.drive/1 que:
RemoteControlCar.new("Red")
|> RemoteControlCar.drive()
# => %RemoteControlCar{
# battery_percentage: 99,
# distance_driven_in_meters: 20,
# nickname: "Red"
# }
Asegúrate de que la función solo acepte un struct RemoteControlCar como argumento.
Actualiza la función RemoteControlCar.drive/1 para que no aumente la distancia recorrida ni disminuya el porcentaje de batería cuando la batería esté descargada (al 0%):
%RemoteControlCar{
battery_percentage: 0,
distance_driven_in_meters: 1980,
nickname: "Red"
}
|> RemoteControlCar.drive()
# => %RemoteControlCar{
# battery_percentage: 0,
# distance_driven_in_meters: 1980,
# nickname: "Red"
# }
Regístrate en Exercism para aprender y dominar Elixir con 58 conceptos168 ejercicios y mentoría humana real, todo gratis.