Tracks
/
Rust
Rust
/
Übungen
/
Stromsparendes eingebettetes Spiel
Stromsparendes eingebettetes Spiel

Stromsparendes eingebettetes Spiel

Lernübung

Einführung

Tupel sind eine einfache Möglichkeit, eine feste Anzahl beliebiger Datentypen zusammenzufassen. Ein Tupel hat keinen bestimmten Namen; sobald du einer Datenstruktur einen Namen gibst, wird daraus ein struct. Die Felder eines Tupels haben keine Namen; auf sie greifst du über Destrukturierung oder über ihre Position zu.

Syntax

Erstellung

Tupel werden immer mit einem Tupelausdruck erstellt:

// pointless but legal
let unit = ();
// single element
let single_element = ("note the comma",);
// two element
let two_element = (123, "elements can be of differing types");

Tupel können eine beliebige Anzahl von Elementen haben.

Zugriff durch Destrukturierung

Du kannst auf die Elemente eines Tupels durch Destrukturierung zugreifen. Das bedeutet, dass du den einzelnen Elementen des Tupels Variablennamen zuweist und das Tupel dabei verbrauchst.

let (elem1, _elem2) = two_element;
assert_eq!(elem1, 123);

Zugriff über die Position

Du kannst auf die Elemente eines Tupels auch über ihren numerischen Positionsindex zugreifen. Die Indexierung beginnt wie immer bei 0.

let notation = single_element.0;
assert_eq!(notation, "note the comma");

Tupelstrukturen

Außerdem wirst du mit Tupelstrukturen arbeiten. Wie normale Strukturen sind sie benannte Typen; anders als normale Strukturen haben sie anonyme Felder. Ihre Syntax ist der normalen Tupelsyntax sehr ähnlich. Du darfst sowohl Destrukturierung als auch den Zugriff über die Position verwenden.

struct TupleStruct(u8, i32);
let my_tuple_struct = TupleStruct(123, -321);
let neg = my_tuple_struct.1;
let TupleStruct(byte, _) = my_tuple_struct;
assert_eq!(neg, -321);
assert_eq!(byte, 123);

Sichtbarkeit von Feldern

Alle Felder anonymer Tupel sind immer öffentlich. Die Felder von Tupelstrukturen haben dagegen jeweils eine eigene Sichtbarkeit, die standardmäßig privat ist, genau wie die Felder normaler Strukturen. Mit dem Modifizierer pub kannst du die Felder öffentlich machen, genau wie bei einer normalen Struktur.

// fails due to private fields
mod tuple { pub struct TupleStruct(u8, i32); }
fn main() { let _my_tuple_struct = tuple::TupleStruct(123, -321); }
// succeeds: fields are public
mod tuple { pub struct TupleStruct(pub u8, pub i32); }
fn main() { let _my_tuple_struct = tuple::TupleStruct(123, -321); }

Anleitung

Du arbeitest an einem Spiel für ein stromsparendes eingebettetes System und musst mehrere Hilfsfunktionen schreiben, die andere Teile des Spiels verwenden werden.

1. Berechne den Quotienten und den Rest einer Division

Der Quotient ist das Ergebnis einer Division.

fn divmod(dividend: i16, divisor: i16) -> (i16, i16)

Beispiel:

assert_eq!(divmod(10, 3), (3, 1));

2. Wähle Elemente an geraden Positionen aus einem Iterator aus

Damit lässt sich später eine Optimierung des Bildschirmpuffers umsetzen, verspricht zumindest dein Chef.

Iteratoren stellen die Methoden bereit, die im Iterator-Trait definiert sind. Diese Dokumentation ist recht umfangreich, weil sie viele Methoden anbieten. Hier sind die wichtigsten Eigenschaften:

  • Ein Iterator ist ein Strom von Elementen beliebiger Länge
  • Er hat eine enumerate-Methode, die für jeden Wert ein Tupel (i, val) zurückgibt
  • Er hat eine filter-Methode, die eine Closure verwendet, um zu entscheiden, ob ein Element des Iterators ausgegeben wird
  • Er hat eine map-Methode, die eine Closure verwendet, um Elemente des Iterators zu verändern

Weil deine Funktion mit jeder Art von Iterator arbeiten kann, verwendet sie impl, um anzuzeigen, dass es sich um eine Trait-Instanz und nicht um ein einfaches Element handelt. Ebenso bedeutet die Syntax <Item=T> nur, dass es keine Rolle spielt, welche Art von Element der Iterator erzeugt; deine Funktion kann die geraden Elemente jedes Iterators liefern.

fn evens<T>(iter: impl Iterator<Item=T>) -> impl Iterator<Item=T>

Beispiele:

let mut even_ints = evens(0_u8..);
assert_eq!(even_ints.next(), Some(0));
assert_eq!(even_ints.next(), Some(2));
assert_eq!(even_ints.next(), Some(4));
assert_eq!(even_ints.next(), Some(6));
let mut evens_from_odds = evens(1_i16..);
assert_eq!(evens_from_odds.next(), Some(1));
assert_eq!(evens_from_odds.next(), Some(3));
assert_eq!(evens_from_odds.next(), Some(5));
assert_eq!(evens_from_odds.next(), Some(7));

3. Berechne die Manhattan-Distanz einer Position vom Ursprung

Damit du bequem mit Koordinaten arbeiten kannst, hast du ein Tupel-Struct Position:

struct Position(i16, i16);

Du musst eine Methode manhattan auf Position implementieren, die die Manhattan-Distanz dieser Position vom Ursprung (Position(0, 0)) zurückgibt.

impl Position {
    fn manhattan(&self) -> i16
}

Beispiel:

assert_eq!(Position(3, 4).manhattan(), 7);
Über GitHub bearbeiten Der Link öffnet sich in einem neuen Fenster oder Tab
Rust Exercism

Bereit, mit Stromsparendes eingebettetes Spiel zu starten?

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