In Rust, le espressioni costanti (const) vengono calcolate al momento della compilazione, permettendo di creare valori che diventano parte del programma ancora prima dell'esecuzione. Tali espressioni sono utilizzate per definire dimensioni di array, valori in strutture statiche, parametri generici e in altre situazioni dove sono necessarie costanti immutabili con un valore ben definito.
In Rust è possibile creare "funzioni costanti" (const fn), che possono essere utilizzate all'interno di altre espressioni const o per inizializzare variabili costanti. Il compilatore garantisce che tale espressione non contenga operazioni non valide (ad esempio, accesso alla memoria).
Esempio:
const fn fib(n: u32) -> u32 { match n { 0 | 1 => 1, _ => fib(n - 1) + fib(n - 2), } } const F8: u32 = fib(8); const ARR: [u32; F8 as usize] = [0; F8 as usize]; // Array di dimensione 34
In questo esempio, il valore di F8 e la dimensione dell'array ARR vengono calcolati al momento della compilazione.
Qual è la differenza tra una funzione const e una funzione normale, e si può dichiarare qualsiasi funzione come const fn?
Risposta:
No, non è possibile dichiarare qualsiasi funzione come const fn. const fn può contenere solo operazioni consentite, che non generano effetti collaterali o non utilizzano memoria non sicura. Ad esempio, non si può aprire un file o allocare memoria dinamicamente in una const fn.
const fn add(x: i32, y: i32) -> i32 { x + y // consentito } // e questo non si compilerà: const fn fail() -> String { // errore! String::from("err") }
Storia
In un progetto, si cercava di calcolare il valore dell'hash di una stringa al momento della compilazione tramite una funzione costante, ma si utilizzavano all'interno di questa funzione metodi standard da
HashMape allocazione di memoria. Il programma non si compilava, generando errori poco chiari relativi a operazioni non valide inconst fn.
Storia
In una grande sviluppo embedded, un sviluppatore ha definito una struttura costante con campi che richiedevano calcolo al momento della compilazione, tuttavia ha utilizzato all'interno dell'inizializzazione una funzione di un crate esterno, non contrassegnata come
const fn. Questo ha portato all'impossibilità di utilizzare questa logica per determinare le dimensioni dei buffer statici.
Storia
Nel codice, si è confusa la differenza tra
staticeconst, cercando di modificare una "costante" durante l'esecuzione e si è ottenuto un UB (Undefined Behavior) implicito, poiché le costanti in Rust non vengono collocate in memoria come valori, ma vengono sostituite dal compilatore nel luogo di utilizzo, il che non implica affatto la loro modifica.