Structs são uma extensão construída sobre mapas, que oferecem verificações em tempo de compilação e valores padrão. Um struct recebe o nome do módulo em que é definido. Para definir um struct, use a construção defstruct. A construção normalmente vem logo depois da definição do módulo. defstruct aceita uma lista de átomos (para valores padrão nil) ou uma lista de palavras-chave (para valores padrão especificados). Os campos sem valor padrão devem vir antes dos campos com valor padrão.
defmodule Plane do
defstruct [:engine, wings: 2]
end
plane = %Plane{}
# => %Plane{engine: nil, wings: 2}
Como structs são construídos sobre mapas, podemos usar a maioria das funções de mapa para obter e manipular valores. O Access Behaviour não é implementado para structs. Em vez disso, recomenda-se usar o operador de acesso estático . para acessar os campos do struct.
obter/buscar valores de campos:
plane = %Plane{}
plane.engine
# => nil
Map.fetch(plane, :wings)
# => {:ok, 2}
atualizar valores de campos
plane = %Plane{}
%{plane | wings: 4}
# => %Plane{engine: nil, wings: 4}
Structs podem ser usados em pattern matching com ou sem o nome do struct.
plane = %Plane{}
%Plane{wings: wings} = plane
%{wings: wings} = plane
Ao incluir o nome do struct no padrão, você garante que tanto o lado esquerdo quanto o direito sejam structs do mesmo 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 o atributo de módulo @enforce_keys com uma lista das chaves dos campos para garantir que os valores sejam inicializados quando o struct for criado. Se uma chave não estiver listada, seu valor será nil, como no exemplo acima. Se uma chave exigida não for inicializada, um erro é lançado.
defmodule User do
@enforce_keys [:username]
defstruct [:username]
end
%User{}
# => (ArgumentError) the following keys must also be given when building struct User: [:username]
Neste exercício, você vai brincar com um carro de controle remoto, aquele que você finalmente juntou dinheiro suficiente para comprar.
Os carros começam com a bateria cheia (100%). Cada vez que você dirige o carro com o controle remoto, ele percorre 20 metros e consome um por cento da bateria. O apelido do carro não é conhecido até que ele seja criado.
O carro de controle remoto tem um display de LED sofisticado que mostra duas informações:
"<METERS> meters"."Battery at <PERCENTAGE>%".Se a bateria estiver em 0%, você não pode mais dirigir o carro e o display da bateria vai mostrar "Battery empty".
Implemente a função RemoteControlCar.new/0 para retornar uma struct de carro de controle remoto novinho em folha:
RemoteControlCar.new()
# => %RemoteControlCar{
# battery_percentage: 100,
# distance_driven_in_meters: 0,
# nickname: "none"
# }
O apelido é exigido pela struct. Certifique-se de que um valor seja inicializado na função new, mas não na struct.
Implemente a função RemoteControlCar.new/1 para retornar uma struct de carro de controle remoto novinho em folha com um apelido fornecido:
RemoteControlCar.new("Blue")
# => %RemoteControlCar{
# battery_percentage: 100,
# distance_driven_in_meters: 0,
# nickname: "Blue"
# }
Implemente a função RemoteControlCar.display_distance/1 para retornar a distância conforme exibida no display de LED:
car = RemoteControlCar.new()
RemoteControlCar.display_distance(car)
# => "0 meters"
Certifique-se de que a função aceite apenas uma struct RemoteControlCar como argumento.
Implemente a função RemoteControlCar.display_battery/1 para retornar a porcentagem da bateria conforme exibida no display de LED:
car = RemoteControlCar.new()
RemoteControlCar.display_battery(car)
# => "Battery at 100%"
Certifique-se de que a função aceite apenas uma struct RemoteControlCar como argumento. Se a bateria estiver em 0%, o display da bateria vai mostrar "Battery empty".
Implemente a função RemoteControlCar.drive/1 que:
RemoteControlCar.new("Red")
|> RemoteControlCar.drive()
# => %RemoteControlCar{
# battery_percentage: 99,
# distance_driven_in_meters: 20,
# nickname: "Red"
# }
Certifique-se de que a função aceite apenas uma struct RemoteControlCar como argumento.
Atualize a função RemoteControlCar.drive/1 para não aumentar a distância percorrida nem diminuir a porcentagem da bateria quando a bateria estiver descarregada (em 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"
# }
Crie sua conta no Exercism para aprender e dominar Elixir com 58 conceitos168 exercícios e mentoria humana de verdade, tudo de graça.