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

Sintassi di Base in Rust

La sintassi di Rust è progettata per essere chiara, esplicita e sicura. Sebbene prenda ispirazione da linguaggi come C e C++, Rust introduce concetti unici che lo distinguono. In questa guida esploreremo gli elementi fondamentali della sintassi di Rust.

La Funzione main

Ogni programma Rust eseguibile deve avere una funzione main, che rappresenta il punto di ingresso dell’applicazione:

fn main() {
    println!("Benvenuto in Rust!");
}

La parola chiave fn dichiara una funzione. Le parentesi graffe {} delimitano il corpo della funzione. A differenza di linguaggi come C, la funzione main in Rust non restituisce un intero per default, anche se è possibile farle restituire un Result.

fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("Main con Result!");
    Ok(())
}

Statement ed Espressioni

In Rust, la distinzione tra statement (istruzioni) ed espressioni è fondamentale.

Statement

Uno statement esegue un’azione ma non restituisce un valore. Le dichiarazioni di variabili con let sono statement:

fn main() {
    let x = 5;        // Statement: dichiarazione di variabile
    let y = 10;       // Statement: dichiarazione di variabile
    println!("{}", x + y);
}

Non è possibile assegnare uno statement a una variabile:

fn main() {
    // let x = (let y = 5); // Errore! `let y = 5` è uno statement
}

Espressioni

Un’espressione restituisce un valore. In Rust, quasi tutto è un’espressione:

fn main() {
    let x = 5 + 3;    // 5 + 3 è un'espressione che vale 8

    let y = {
        let a = 10;
        a * 2          // Nessun punto e virgola: è un'espressione
    };                 // y vale 20

    println!("x = {}, y = {}", x, y);
}

Anche if è un’espressione in Rust:

fn main() {
    let condizione = true;
    let numero = if condizione { 5 } else { 10 };
    println!("numero = {}", numero); // Stampa: numero = 5
}

Il Ruolo del Punto e Virgola

In Rust, il punto e virgola ; ha un significato preciso: trasforma un’espressione in uno statement, scartando il valore restituito.

fn cinque() -> i32 {
    5          // Espressione: restituisce 5
}

fn niente() {
    5;         // Statement: il valore 5 viene scartato
}

fn main() {
    let a = cinque();
    println!("a = {}", a); // Stampa: a = 5

    niente(); // Non restituisce nulla (restituisce il tipo unit `()`)
}

Questa distinzione è fondamentale: dimenticare o aggiungere un punto e virgola può cambiare completamente il comportamento del codice.

Blocchi di Codice e Scope

Un blocco di codice delimitato da parentesi graffe {} crea un nuovo scope (ambito di visibilitĂ ):

fn main() {
    let x = 10;

    {
        let y = 20;
        println!("Dentro il blocco: x = {}, y = {}", x, y);
    } // y esce dallo scope qui

    // println!("{}", y); // Errore! y non esiste piĂą

    println!("Fuori dal blocco: x = {}", x);
}

I blocchi sono anche espressioni e restituiscono l’ultima espressione contenuta:

fn main() {
    let risultato = {
        let base = 10;
        let altezza = 5;
        base * altezza  // Valore restituito dal blocco
    };

    println!("Area = {}", risultato); // Stampa: Area = 50
}

Convenzioni di Denominazione

Rust ha convenzioni di denominazione ben definite che il compilatore stesso segnala se non vengono rispettate:

snake_case per funzioni e variabili

fn calcola_area(base: f64, altezza: f64) -> f64 {
    base * altezza
}

fn main() {
    let numero_studenti = 30;
    let area_rettangolo = calcola_area(5.0, 3.0);
    println!("Studenti: {}, Area: {}", numero_studenti, area_rettangolo);
}

CamelCase per tipi e trait

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

enum ColoreSemaforo {
    Rosso,
    Giallo,
    Verde,
}

fn main() {
    let punto = PuntoCartesiano { x: 1.0, y: 2.0 };
    let colore = ColoreSemaforo::Verde;
}

SCREAMING_SNAKE_CASE per costanti

const VELOCITA_LUCE: f64 = 299_792_458.0;
const MAX_GIOCATORI: u32 = 100;

fn main() {
    println!("La velocità della luce è {} m/s", VELOCITA_LUCE);
}

Le Macro con il Punto Esclamativo

In Rust, le chiamate che terminano con ! sono macro, non funzioni. Le macro sono un meccanismo di metaprogrammazione che genera codice a tempo di compilazione:

fn main() {
    println!("Questa è una macro!");        // Stampa con newline
    print!("Senza newline ");               // Stampa senza newline
    eprintln!("Errore su stderr!");          // Stampa su stderr

    let v = vec![1, 2, 3];                  // Macro per creare un Vec
    let s = format!("Il vettore ha {} elementi", v.len()); // Formattazione
    println!("{}", s);

    // La macro todo!() è utile come placeholder
    // todo!("Implementare questa funzione");

    // La macro dbg!() è utile per il debug
    let x = 42;
    dbg!(x); // Stampa: [src/main.rs:14] x = 42
}

Le macro si distinguono dalle funzioni perché possono accettare un numero variabile di argomenti e generare codice durante la compilazione.

Conclusione

La sintassi di Rust è progettata per essere esplicita e prevenire errori comuni. La distinzione tra statement ed espressioni, il ruolo significativo del punto e virgola e le convenzioni di denominazione rigorose contribuiscono a rendere il codice Rust leggibile e manutenibile. Comprendere questi concetti fondamentali è il primo passo per padroneggiare il linguaggio e sfruttare appieno il suo sistema di tipi e le sue garanzie di sicurezza.