Tracks
/
Elixir
Elixir
/
Übungen
/
Ferngesteuertes Auto
Ferngesteuertes Auto

Ferngesteuertes Auto

Lernübung

Einführung

Structs

Structs sind eine Erweiterung, die auf Maps aufbaut und Prüfungen zur Kompilierzeit sowie Standardwerte bietet. Ein Struct ist nach dem Modul benannt, in dem es definiert wird. Um ein Struct zu definieren, verwendest du das Konstrukt defstruct. Das Konstrukt folgt normalerweise direkt auf die Moduldefinition. defstruct akzeptiert entweder eine Liste von Atomen (für Standardwerte nil) oder eine Keyword-Liste (für festgelegte Standardwerte). Die Felder ohne Standardwerte müssen vor den Feldern mit Standardwerten stehen.

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

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

Auf Felder zugreifen und sie aktualisieren

Da Structs auf Maps aufbauen, können wir die meisten Map-Funktionen verwenden, um Werte abzurufen und zu verändern. Das Access Behaviour ist für Structs nicht implementiert. Stattdessen empfiehlt es sich, den statischen Zugriffsoperator . zu verwenden, um auf Struct-Felder zuzugreifen.

  • Feldwerte abrufen:

    plane = %Plane{}
    plane.engine
    # => nil
    Map.fetch(plane, :wings)
    # => {:ok, 2}
    
  • Feldwerte aktualisieren

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

Pattern Matching

Structs können im Pattern Matching mit oder ohne den Struct-Namen verwendet werden.

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

Wenn du den Struct-Namen im Muster angibst, stellst du sicher, dass sowohl die linke als auch die rechte Seite Structs desselben Typs sind.

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

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

Die Initialisierung von Feldwerten erzwingen

Wir können das Modulattribut @enforce_keys mit einer Liste der Feldschlüssel verwenden, um sicherzustellen, dass die Werte initialisiert werden, wenn das Struct erstellt wird. Wenn ein Schlüssel nicht aufgeführt ist, ist sein Wert nil, wie im obigen Beispiel zu sehen. Wenn ein erzwungener Schlüssel nicht initialisiert wird, wird ein Fehler ausgelöst.

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

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

Anleitung

In dieser Übung beschäftigst du dich mit einem ferngesteuerten Auto, für das du endlich genug Geld gespart hast.

Autos starten mit vollen (100 %) Akkus. Jedes Mal, wenn du das Auto mit der Fernbedienung fährst, legt es 20 Meter zurück und verbraucht ein Prozent des Akkus. Der Spitzname des Autos ist erst bekannt, wenn das Auto erstellt wird.

Das ferngesteuerte Auto hat ein schickes LED-Display, das zwei Informationen anzeigt:

  • Die insgesamt gefahrene Strecke, angezeigt als: "<METERS> meters".
  • Die verbleibende Akkuladung, angezeigt als: "Battery at <PERCENTAGE>%".

Wenn der Akku bei 0 % ist, kannst du das Auto nicht mehr fahren und die Akkuanzeige zeigt "Battery empty" an.

1. Erstelle ein brandneues ferngesteuertes Auto

Implementiere die Funktion RemoteControlCar.new/0, die ein brandneues ferngesteuertes Auto-Struct zurückgibt:

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

Der Spitzname ist im Struct erforderlich. Stelle sicher, dass ein Wert in der Funktion new initialisiert wird, aber nicht im Struct.

2. Erstelle ein brandneues ferngesteuertes Auto mit einem Spitznamen

Implementiere die Funktion RemoteControlCar.new/1, die ein brandneues ferngesteuertes Auto-Struct mit einem übergebenen Spitznamen zurückgibt:

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

3. Zeige die Strecke an

Implementiere die Funktion RemoteControlCar.display_distance/1, die die Strecke so zurückgibt, wie sie auf dem LED-Display angezeigt wird:

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

Stelle sicher, dass die Funktion nur ein RemoteControlCar-Struct als Argument akzeptiert.

4. Zeige den Akkustand an

Implementiere die Funktion RemoteControlCar.display_battery/1, die den Akkustand so zurückgibt, wie er auf dem LED-Display angezeigt wird:

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

Stelle sicher, dass die Funktion nur ein RemoteControlCar-Struct als Argument akzeptiert. Wenn der Akku bei 0 % ist, zeigt die Akkuanzeige "Battery empty" an.

5. Fahren verändert den Akku und die gefahrene Strecke

Implementiere die Funktion RemoteControlCar.drive/1, die:

  • die Anzahl der gefahrenen Meter um 20 erhöht
  • 1 % des Akkus verbraucht
RemoteControlCar.new("Red")
|> RemoteControlCar.drive()

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

Stelle sicher, dass die Funktion nur ein RemoteControlCar-Struct als Argument akzeptiert.

6. Fahren mit leerem Akku berücksichtigen

Aktualisiere die Funktion RemoteControlCar.drive/1, sodass sie die gefahrene Strecke nicht erhöht und den Akkustand nicht verringert, wenn der Akku leer ist (bei 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"
#    }
Über GitHub bearbeiten Der Link öffnet sich in einem neuen Fenster oder Tab
Elixir Exercism

Bereit, mit Ferngesteuertes Auto zu starten?

Melde dich bei Exercism an, um Elixir mit 58 Konzepte168 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.