Parcours
/
Elixir
Elixir
/
Exercices
/
Voiture télécommandée
Voiture télécommandée

Voiture télécommandée

Exercice d'apprentissage

Introduction

Structs

Les structs sont une extension construite au-dessus des maps, qui apportent des vérifications à la compilation et des valeurs par défaut. Un struct porte le nom du module dans lequel il est défini. Pour définir un struct, on utilise la construction defstruct. Celle-ci suit généralement immédiatement la définition du module. defstruct accepte soit une liste d'atomes (pour des valeurs par défaut à nil), soit une liste de mots-clés (pour des valeurs par défaut spécifiques). Les champs sans valeur par défaut doivent venir avant ceux qui en ont une.

defmodule Plane do
  defstruct [:engine, wings: 2]
end

plane = %Plane{}
# => %Plane{engine: nil, wings: 2}

Accède aux champs et mets-les à jour

Comme les structs sont construits sur des maps, on peut utiliser la plupart des fonctions associées aux maps pour obtenir et manipuler des valeurs. Le comportement Access n'est pas implémenté pour les structs. Il est recommandé d'utiliser plutôt l'opérateur d'accès statique . pour accéder aux champs d'un struct.

  • obtenir/récupérer les valeurs des champs :

    plane = %Plane{}
    plane.engine
    # => nil
    Map.fetch(plane, :wings)
    # => {:ok, 2}
    
  • mettre à jour les valeurs des champs

    plane = %Plane{}
    %{plane | wings: 4}
    # => %Plane{engine: nil, wings: 4}
    

Filtrage par motif

Les structs peuvent être utilisés en filtrage par motif, avec ou sans le nom du struct.

plane = %Plane{}
%Plane{wings: wings} = plane
%{wings: wings} = plane

En incluant le nom du struct dans le motif, on s'assure que le côté gauche et le côté droit sont bien des structs du même type.

defmodule Helicopter do
  defstruct [:engine, rotors: 1]
end

%Plane{} = %Helicopter{}
# => (MatchError) no match of right hand side value: %Helicopter{engine: nil, rotors: 1}

Impose l'initialisation des valeurs des champs

On peut utiliser l'attribut de module @enforce_keys avec une liste des clés de champ pour s'assurer que les valeurs sont initialisées à la création du struct. Si une clé n'est pas listée, sa valeur sera nil, comme dans l'exemple ci-dessus. Si une clé soumise à @enforce_keys n'est pas initialisée, une erreur est levée.

defmodule User do
  @enforce_keys [:username]
  defstruct [:username]
end

%User{}
# => (ArgumentError) the following keys must also be given when building struct User: [:username]

Instructions

Dans cet exercice, tu vas jouer avec une voiture télécommandée, pour laquelle tu as enfin économisé assez d'argent pour l'acheter.

Les voitures commencent avec une batterie pleine (100 %). Chaque fois que tu conduis la voiture avec la télécommande, elle parcourt 20 mètres et consomme un pour cent de la batterie. Le surnom de la voiture n'est pas connu avant sa création.

La voiture télécommandée possède un écran LED sophistiqué qui affiche deux informations :

  • La distance totale qu'elle a parcourue, affichée sous la forme : "<METERS> meters".
  • La charge restante de la batterie, affichée sous la forme : "Battery at <PERCENTAGE>%".

Si la batterie est à 0 %, tu ne peux plus conduire la voiture et l'affichage de la batterie affichera "Battery empty".

1. Crée une toute nouvelle voiture télécommandée

Implémente la fonction RemoteControlCar.new/0 pour renvoyer une toute nouvelle structure de voiture télécommandée :

RemoteControlCar.new()
# => %RemoteControlCar{
#      battery_percentage: 100,
#      distance_driven_in_meters: 0,
#      nickname: "none"
#    }

Le surnom est requis par la structure ; assure-toi qu'une valeur est initialisée dans la fonction new, mais pas dans la structure.

2. Crée une toute nouvelle voiture télécommandée avec un surnom

Implémente la fonction RemoteControlCar.new/1 pour renvoyer une toute nouvelle structure de voiture télécommandée avec un surnom fourni :

RemoteControlCar.new("Blue")
# => %RemoteControlCar{
#      battery_percentage: 100,
#      distance_driven_in_meters: 0,
#      nickname: "Blue"
#    }

3. Affiche la distance

Implémente la fonction RemoteControlCar.display_distance/1 pour renvoyer la distance telle qu'affichée sur l'écran LED :

car = RemoteControlCar.new()
RemoteControlCar.display_distance(car)
# => "0 meters"

Assure-toi que la fonction n'accepte qu'une structure RemoteControlCar comme argument.

4. Affiche le pourcentage de batterie

Implémente la fonction RemoteControlCar.display_battery/1 pour renvoyer le pourcentage de batterie tel qu'affiché sur l'écran LED :

car = RemoteControlCar.new()
RemoteControlCar.display_battery(car)
# => "Battery at 100%"

Assure-toi que la fonction n'accepte qu'une structure RemoteControlCar comme argument. Si la batterie est à 0 %, l'affichage de la batterie affichera "Battery empty".

5. La conduite modifie la batterie et la distance parcourue

Implémente la fonction RemoteControlCar.drive/1 qui :

  • augmente de 20 le nombre de mètres parcourus
  • consomme 1 % de la batterie
RemoteControlCar.new("Red")
|> RemoteControlCar.drive()

# => %RemoteControlCar{
#      battery_percentage: 99,
#      distance_driven_in_meters: 20,
#      nickname: "Red"
#    }

Assure-toi que la fonction n'accepte qu'une structure RemoteControlCar comme argument.

6. Prends en compte la conduite avec une batterie à plat

Mets à jour la fonction RemoteControlCar.drive/1 pour qu'elle n'augmente pas la distance parcourue et ne diminue pas le pourcentage de batterie lorsque la batterie est déchargée (à 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"
#    }
Modifie via GitHub Le lien s'ouvre dans une nouvelle fenêtre ou un nouvel onglet
Elixir Exercism

Prêt à commencer Voiture télécommandée ?

Inscris-toi sur Exercism pour apprendre et maîtriser Elixir avec 58 concepts168 exercices, et un vrai mentorat humain, le tout gratuitement.