From în Rust

Trait-ul pentru conversii care nu pot eșua: Tinta::from(x). Implementându-l, primești gratuit și x.into().

Sintaxă
impl From<Sursa> for Tinta {
    fn from(valoare: Sursa) -> Self { ... }
}

let t = Tinta::from(sursa);
let t: Tinta = sursa.into();

Ce face From

From<T> descrie cum se construiește un tip din altul, fără posibilitate de eroare: String::from("text"), f64::from(3_i32), Vec::from([1, 2, 3]). Convenția este să-l folosești doar pentru conversii sigure și evidente; pentru cele care pot eșua există TryFrom.

Când scrii impl From<A> for B, Rust îți dă automat și impl Into<B> for A, deci poți scrie și let b: B = a.into();. De aceea se implementează mereu From, niciodată Into direct.

Un loc important este tratarea erorilor: operatorul ? convertește automat eroarea cu From. Dacă tipul tău de eroare are impl From<ParseIntError>, poți folosi ? pe parse() într-o funcție care returnează eroarea ta.

Parametri

Parametru Descriere
from(valoare) Primește valoarea sursă (prin valoare, deci o consumă) și returnează tipul nou.

Ce returnează

O valoare de tipul țintă.

Exemple

Exemplul 1: Conversie între două tipuri proprii

struct Celsius(f64);
struct Fahrenheit(f64);

impl From<Celsius> for Fahrenheit {
    fn from(c: Celsius) -> Self {
        Fahrenheit(c.0 * 9.0 / 5.0 + 32.0)
    }
}

fn main() {
    let f = Fahrenheit::from(Celsius(25.0));
    println!("25°C = {:.1}°F", f.0);

    let g: Fahrenheit = Celsius(-10.0).into();   // into vine automat
    println!("-10°C = {:.1}°F", g.0);

    println!("{} {:?} {}", f64::from(7_i32), Vec::from([1, 2]), String::from('ș'));
}

Rezultat

25°C = 77.0°F
-10°C = 14.0°F
7 [1, 2] ș

Exemplul 2: From pentru erori și operatorul ?

use std::fmt;
use std::num::ParseIntError;

#[derive(Debug)]
enum EroareComanda {
    CantitateInvalida(ParseIntError),
    StocInsuficient,
}

impl From<ParseIntError> for EroareComanda {
    fn from(e: ParseIntError) -> Self {
        EroareComanda::CantitateInvalida(e)
    }
}

impl fmt::Display for EroareComanda {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            EroareComanda::CantitateInvalida(e) => write!(f, "cantitate invalidă: {e}"),
            EroareComanda::StocInsuficient => write!(f, "nu avem destul în stoc"),
        }
    }
}

fn comanda(text: &str, stoc: u32) -> Result<u32, EroareComanda> {
    let cantitate: u32 = text.trim().parse()?;   // ParseIntError devine EroareComanda
    if cantitate > stoc {
        return Err(EroareComanda::StocInsuficient);
    }
    Ok(stoc - cantitate)
}

fn main() {
    for t in ["3", "abc", "50"] {
        match comanda(t, 10) {
            Ok(rest) => println!("{t}: comandă primită, rămân {rest}"),
            Err(e) => println!("{t}: {e}"),
        }
    }
}

Rezultat

3: comandă primită, rămân 7
abc: cantitate invalidă: invalid digit found in string
50: nu avem destul în stoc

Greșeli frecvente

  • Implementezi Into în loc de From. Merge, dar pierzi From; implementează From și primești ambele.
  • Folosești From pentru o conversie care poate pierde date sau eșua (de exemplu i64 → u8). Pentru acestea este TryFrom.

Comenzi înrudite

  • Into: Perechea lui From văzută din partea sursei: x.into() convertește în tipul cerut; util în parametri generici.
  • TryFrom: Conversii care pot eșua și returnează Result: u8::try_from(300) dă Err. Implementarea aduce și try_into().
  • FromStr: Trait-ul care face un tip „citibil” din text; după implementare, „…”.parse::<Tip>() funcționează.
  • String::from: Creează un String nou (deținut) din &str, char sau alt text, copiind conținutul pe heap.