From und Into
Teil des Abschnitts Objektorientierte Programmierung der Rust-Journey von Coddy. Lektion 57 von 61.
Die Konvertierung zwischen Typen ist eine häufige Aufgabe in Rust. Das From-Trait bietet eine standardisierte Möglichkeit, zu definieren, wie ein Typ aus einem anderen erstellt werden kann. Wenn du From implementierst, erhältst du das Into-Trait automatisch und kostenlos.
Um From zu implementieren, definierst du, wie dein Typ aus einem anderen Typ erstellt wird:
struct Meters(f64);
struct Kilometers(f64);
impl From<Kilometers> for Meters {
fn from(km: Kilometers) -> Self {
Meters(km.0 * 1000.0)
}
}
Jetzt kannst du entweder mit der Funktion from oder der Methode into konvertieren:
let distance = Kilometers(5.0);
// From explizit verwenden
let m1 = Meters::from(distance);
// Into verwenden (funktioniert, weil From implementiert ist)
let distance = Kilometers(3.0);
let m2: Meters = distance.into();
Die into()-Methode erfordert eine Typannotation, da Rust wissen muss, in welchen Typ du konvertierst. Dieses Muster ist besonders nützlich, wenn du Hilfsstrukturen hast, die in deine Haupttypen konvertiert werden müssen, beispielsweise beim Umwandeln von Konfigurationsdaten in ein initialisiertes Objekt oder beim Transformieren von rohen Eingabedaten in eine validierte Struktur.
Aufgabe
EinfachLass uns ein Temperaturumrechnungssystem mit dem From-Trait erstellen! Du wirst zwei Temperaturtypen erstellen, Celsius und Fahrenheit, und mithilfe der standardmäßigen Konversions-Traits von Rust Umrechnungen zwischen ihnen implementieren.
Du wirst deinen Code auf zwei Dateien verteilen:
temperature.rs: Definiere zwei öffentliche Newtype-Strukturen,CelsiusundFahrenheit, die beide einenf64umschließen. Implementiere denFrom-Trait, umCelsiusmithilfe der FormelFahrenheitinfahrenheit = celsius × 1.8 + 32.0umzuwandeln. Füge außerdem jeder Struktur einevalue-Methode hinzu, die den innerenf64zurückgibt.main.rs: Binde dein Temperaturmodul ein und führe beide Umrechnungsansätze vor. Erstelle aus der bereitgestellten Eingabe einenCelsius-Wert und wandle ihn anschließend mitFahrenheitinFahrenheit::from()um. Erstelle einen weiterenCelsius-Wert und wandle ihn mithilfe der.into()-Methode um. Gib beide Ergebnisse aus.
Die Umrechnungsformel von Celsius in Fahrenheit lautet: mit 1.8 multiplizieren und 32 addieren. Denke daran, dass die Implementierung von From<Celsius> for Fahrenheit dir automatisch kostenlos den Into<Fahrenheit>-Trait für Celsius bereitstellt!
Beide Temperaturen werden als ganze Zahlen ausgegeben: Wandle jeden f64 mit as i64 um, wodurch die Dezimalstellen in Richtung null abgeschnitten werden. Daher wird eine Eingabe von 36.6 als 36C ausgegeben, und die daraus umgerechneten 97.88 Grad Fahrenheit werden als 97F ausgegeben. Es wird niemals aufgerundet.
Deine Ausgabe sollte beide Umrechnungen in diesem Format anzeigen:
From: {celsius1}C = {fahrenheit1}F
Into: {celsius2}C = {fahrenheit2}FZum Beispiel bei den Eingaben 0 und 100:
From: 0C = 32F
Into: 100C = 212FUnd bei den Eingaben 25 und -40:
From: 25C = 77F
Into: -40C = -40FDu erhältst zwei Eingaben: den ersten Celsius-Wert (als f64 parsen) und den zweiten Celsius-Wert (als f64 parsen).
Probier es selbst
mod temperature;
use temperature::{Celsius, Fahrenheit};
fn main() {
// Eingabe lesen
let mut input1 = String::new();
std::io::stdin().read_line(&mut input1).expect("Failed to read line");
let celsius1: f64 = input1.trim().parse().expect("Invalid number");
let mut input2 = String::new();
std::io::stdin().read_line(&mut input2).expect("Failed to read line");
let celsius2: f64 = input2.trim().parse().expect("Invalid number");
// TODO: Erstelle einen Celsius-Wert aus celsius1
// TODO: Konvertiere ihn zu Fahrenheit mit Fahrenheit::from()
// TODO: Erstelle einen weiteren Celsius-Wert aus celsius2
// TODO: Konvertiere ihn zu Fahrenheit mit .into()
// TODO: Gib die Ergebnisse im folgenden Format aus:
// From: {celsius1}C = {fahrenheit1}F
// Into: {celsius2}C = {fahrenheit2}F
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Methoden und Verhalten
Einführung in ImplementierungsblöckeDer Self-ParameterVeränderliche MethodenAssoziierte FunktionenMehrere ImplementierungsblöckeMethod ChainingRückblick – Rechteck-Aktionen4Projekt: Virtuelles Haustier
Das Haustier definierenDas Haustier füttern7Standard-Traits
Das Debug-TraitDas Display-TraitClone und CopyGleichheits-TraitsZusammenfassung – Druckbarer Punkt10Projekt: Dokumentensystem
Das Draw-TraitText-Komponente2Kapselung und Module
Grundlagen der ModuleDas Public-SchlüsselwortPrivate FelderGetterSetterWiederholung – Sicherer Tresor5Generics
Generische StructsGenerische MethodenMehrere generische TypenGenerische FunktionenZusammenfassung - Koordinatenpunkt8Traits als Einschränkungen
Syntax für Trait BoundsMehrfache BoundsDie Where-KlauselTypen mit Traits zurückgebenRückblick – Generischer Drucker11Design Patterns in Rust
Newtype-PatternKompositionDas Drop-TraitFrom und IntoZusammenfassung – Smart Pointer Mock3Fortgeschrittene Enums
Enums mit DatenMethoden für EnumsMatching von DatenvariantenDas Option-Enum erneut betrachtetZusammenfassung – Shape-Enum6Definition von Traits
Was ist ein Trait?Traits implementierenStandardimplementierungenStandardimplementierungen überschreibenTraits mit ParameternZusammenfassung – Media PlayerÜbe selbstständig: Online-Rust-Compiler