From und Into
Teil des Abschnitts Object Oriented Programming der Rust-Journey von Coddy — Lektion 57 von 61.
Das Konvertieren 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 Sie From implementieren, erhalten Sie das Into-Trait automatisch kostenlos dazu.
Um From zu implementieren, definieren Sie, wie Ihr 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 können Sie entweder mit der from-Funktion oder der into-Methode konvertieren:
let distance = Kilometers(5.0);
// From explizit verwenden
let m1 = Meters::from(distance);
// Into verwenden (funktioniert, da From implementiert ist)
let distance = Kilometers(3.0);
let m2: Meters = distance.into();
Die Methode into() erfordert eine Typannotation, da Rust wissen muss, in welchen Typ Sie konvertieren. Dieses Muster ist besonders nützlich, wenn Sie Hilfs-Structs haben, die in Ihre Haupttypen konvertiert werden müssen – etwa beim Konvertieren von Konfigurationsdaten in ein initialisiertes Objekt oder beim Transformieren von Roheingaben in eine validierte Struktur.
Aufgabe
EinfachLassen Sie uns ein Temperaturumrechnungssystem mit dem From-Trait bauen! Sie werden zwei Temperaturtypen erstellen—Celsius und Fahrenheit—und Umrechnungen zwischen ihnen unter Verwendung der Standard-Umrechnungs-Traits von Rust implementieren.
Sie werden Ihren Code auf zwei Dateien aufteilen:
temperature.rs: Definieren Sie zwei öffentliche Newtype-Structs—CelsiusundFahrenheit—die beide einf64umschließen. Implementieren Sie denFrom-Trait, umCelsiusinFahrenheitumzurechnen, unter Verwendung der Formel:fahrenheit = celsius × 1.8 + 32.0. Fügen Sie außerdem jedem Struct einevalue-Methode hinzu, die das inneref64zurückgibt.main.rs: Binden Sie Ihr Temperatur-Modul ein und demonstrieren Sie beide Umrechnungsansätze. Erstellen Sie einenCelsius-Wert aus der bereitgestellten Eingabe und konvertieren Sie ihn dann mitFahrenheit::from()inFahrenheit. Erstellen Sie einen weiterenCelsius-Wert und konvertieren Sie ihn mit der.into()-Methode. Geben Sie beide Ergebnisse aus.
Die Umrechnungsformel von Celsius nach Fahrenheit lautet: mit 1.8 multiplizieren und 32 addieren. Denken Sie daran, dass die Implementierung von From<Celsius> for Fahrenheit Ihnen automatisch den Into<Fahrenheit>-Trait für Celsius kostenlos zur Verfügung stellt!
Ihre 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 = -40FSie erhalten zwei Eingaben: den ersten Celsius-Wert (als f64 parsen) und den zweiten Celsius-Wert (als f64 parsen).
Spickzettel
Das From-Trait bietet eine standardisierte Möglichkeit, zwischen Typen zu konvertieren. Wenn Sie From implementieren, erhalten Sie das Into-Trait automatisch dazu.
Um From zu implementieren, definieren Sie, wie Ihr Typ aus einem anderen Typ konstruiert wird:
struct Meters(f64);
struct Kilometers(f64);
impl From<Kilometers> for Meters {
fn from(km: Kilometers) -> Self {
Meters(km.0 * 1000.0)
}
}
Sie können die Konvertierung entweder mit der from-Funktion oder der into-Methode durchführen:
let distance = Kilometers(5.0);
// Using From explicitly
let m1 = Meters::from(distance);
// Using Into (requires type annotation)
let distance = Kilometers(3.0);
let m2: Meters = distance.into();
Die into()-Methode erfordert eine Typannotation, damit Rust weiß, in welchen Typ Sie konvertieren möchten.
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 in Fahrenheit mit Fahrenheit::from()
// TODO: Erstelle einen weiteren Celsius-Wert aus celsius2
// TODO: Konvertiere ihn in Fahrenheit mit .into()
// TODO: Gib die Ergebnisse in folgendem 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 Object Oriented Programming
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