00
:
00
:
00
:
00
•Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

Conversione di Tipi in Rust

Rust non esegue conversioni implicite tra tipi. Ogni conversione deve essere esplicita, garantendo sicurezza e chiarezza nel codice.

Casting con as

Il keyword as converte tra tipi primitivi:

fn main() {
    // Numeri
    let x: i32 = 42;
    let y: f64 = x as f64;       // i32 → f64
    let z: u8 = x as u8;         // i32 → u8 (troncamento se fuori range)

    let grande: i64 = 1_000_000;
    let piccolo: i16 = grande as i16; // Attenzione: overflow silenzioso!

    // Char e numeri
    let c = 'A';
    let n = c as u32;    // 65
    let c2 = 65u8 as char; // 'A'

    // Bool
    let b = true as i32; // 1
}

Attenzione: as può causare perdita di dati senza avvisi!

From e Into

I trait From e Into per conversioni sicure e infallibili:

fn main() {
    // From - conversione esplicita
    let s = String::from("ciao");
    let n: i64 = i64::from(42_i32);

    // Into - conversione inversa (implementata automaticamente)
    let s: String = "ciao".into();
    let n: f64 = 42_i32.into();
}

Implementare From per Tipi Personalizzati

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 c = Celsius(100.0);
    let f = Fahrenheit::from(c);
    // oppure
    let c2 = Celsius(0.0);
    let f2: Fahrenheit = c2.into(); // Into è automatico se From è implementato
}

TryFrom e TryInto

Per conversioni che possono fallire:

use std::convert::TryFrom;

fn main() {
    // i32 → u8 potrebbe fallire
    let grande: i32 = 300;
    match u8::try_from(grande) {
        Ok(n) => println!("Convertito: {}", n),
        Err(e) => println!("Errore: {}", e), // Questo caso
    }

    let piccolo: i32 = 42;
    let n: u8 = u8::try_from(piccolo).unwrap(); // OK: 42

    // Con TryInto
    let risultato: Result<u8, _> = grande.try_into();
}

ToString e Display

Conversione in stringa tramite il trait Display:

use std::fmt;

struct Punto {
    x: f64,
    y: f64,
}

impl fmt::Display for Punto {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

fn main() {
    let p = Punto { x: 3.0, y: 4.0 };
    let s = p.to_string(); // "(3, 4)" - grazie a Display
    let n = 42.to_string(); // "42"
}

FromStr e parse

Conversione da stringa a un tipo:

fn main() {
    let n: i32 = "42".parse().unwrap();
    let f: f64 = "3.14".parse().unwrap();
    let b: bool = "true".parse().unwrap();

    // Gestione errore
    match "abc".parse::<i32>() {
        Ok(n) => println!("{}", n),
        Err(e) => println!("Non è un numero: {}", e),
    }
}

Implementare FromStr

use std::str::FromStr;

struct Colore { r: u8, g: u8, b: u8 }

impl FromStr for Colore {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parti: Vec<u8> = s.split(',')
            .map(|p| p.trim().parse().map_err(|_| "Numero non valido".to_string()))
            .collect::<Result<Vec<_>, _>>()?;

        if parti.len() != 3 {
            return Err("Servono 3 valori".to_string());
        }
        Ok(Colore { r: parti[0], g: parti[1], b: parti[2] })
    }
}

fn main() {
    let c: Colore = "255, 128, 0".parse().unwrap();
}

Conclusione

Rust offre un sistema di conversione ricco e sicuro. Usa as per casting primitivi veloci, From/Into per conversioni infallibili, TryFrom/TryInto per conversioni fallibili, e FromStr/parse per convertire da stringhe. Implementa sempre From (non Into) per i tuoi tipi: Into viene derivato automaticamente.