Rust — un linguaggio di programmazione di sistema con garanzie di sicurezza della memoria in fase di compilazione. Sviluppato da Mozilla Research nel 2010 sotto la direzione di Graydon Hoare. Rust previene intere classi di vulnerabilità: puntatori nulli, riferimenti pendenti e race condition. Nello sviluppo mobile, Rust viene utilizzato per moduli nativi, SDK multipiattaforma e WebAssembly. Secondo Stack Overflow Survey (2025), Rust è il «linguaggio più amato» per il nono anno consecutivo.
Punti chiave
Rust è un linguaggio di programmazione di sistema tipizzato staticamente con astrazioni a costo zero (zero-cost abstractions). Rust garantisce la sicurezza della memoria senza garbage collector grazie al suo sistema di ownership, borrowing e lifetimes. Il compilatore Rust è uno dei più severi: rifiuta il codice che in C++ causerebbe comportamento indefinito.
Rust compila tramite LLVM in codice nativo per tutte le architetture: ARM, x86, RISC-V, WebAssembly. Il toolkit include: rustup (installer), rustc (compilatore), cargo (gestore di pacchetti e strumento di build). Cargo.toml — analogo a package.json, contiene le dipendenze da crates.io. L'ultima versione stabile è Rust 1.81 (2025).
Aree chiave di applicazione di Rust nello sviluppo mobile: librerie native (Android NDK, iOS), SDK multipiattaforma (Firefox, Dropbox), sostituzione di C++ in sezioni critiche per le prestazioni, WebAssembly per applicazioni ibride. Google utilizza Rust in AOSP (Android Open Source Project) per i componenti Bluetooth, Wi-Fi e NFC.
Per la cross-compilazione verso Android, sono necessari toolchain di destinazione: rustup target add aarch64-linux-android armv7-linux-androideabi. Per iOS — aarch64-apple-ios x86_64-apple-ios. cargo-ndk (per Android) e cargo-lipo (per iOS) semplificano il processo di build.
# Installazione di Rust e piattaforme target per lo sviluppo mobile
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
$ rustup target add aarch64-linux-android
$ rustup target add armv7-linux-androideabi
$ rustup target add aarch64-apple-ios
$ rustup target add x86_64-apple-ios
# Installazione di cargo-ndk per build Android
$ cargo install cargo-ndk
# Build per Android
$ cargo ndk -t arm64-v8a -o ./jniLibs build --releaseOwnership (proprietà) è il concetto fondamentale di Rust. Ogni valore ha esattamente un proprietario. Quando viene assegnato o passato a una funzione, la proprietà viene trasferita (move). Dopo il trasferimento, il vecchio proprietario non può utilizzare il valore. Questo elimina il doppio rilascio di memoria e i puntatori pendenti.
Borrowing (prestito) consente di utilizzare temporaneamente un riferimento a un valore senza trasferirne la proprietà. Il riferimento &T (immutabile) — qualsiasi numero di lettori. Il riferimento &mut T (mutabile) — esattamente uno scrittore, nessun lettore. Il compilatore verifica queste regole in fase di compilazione.
fn process_data(data: &mut Vec<i32>) {
for item in data.iter_mut() {
*item *= 2;
}
}
fn main() {
let mut numbers = vec![1, 2, 3, 4, 5];
process_data(&mut numbers);
println!("Processed: {:?}", numbers);
let first = &numbers[0]; // prestito immutabile
println!("First: {}", first);
}process_data prende un riferimento mutabile a Vec e raddoppia ogni elemento. iter_mut() restituisce un iteratore con riferimenti mutabili. *item dereferenzia il riferimento per l'assegnazione. Dopo process_data, numbers rimane accessibile — la proprietà non è stata trasferita, solo prestata.
Lifetimes ('a) — annotazioni che collegano le durate dei riferimenti. Il compilatore le utilizza per verificare che un riferimento non sopravviva ai dati a cui punta. Nella maggior parte dei casi, i lifetimes vengono dedotti automaticamente — è necessario specificarli solo nelle firme delle funzioni con riferimenti.
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
fn main() {
let string1 = String::from("rust");
let result;
{
let string2 = String::from("mobile");
result = longest(string1.as_str(), string2.as_str());
println!("Longest: {}", result);
} // string2 vive fino a questa parentesi, result è valido all'interno
// println!("{}", result); // errore: string2 è morto
}Rust compila in librerie native per Android (.so tramite NDK) e iOS (.a librerie statiche). Google supporta ufficialmente Rust in Android Open Source Project (AOSP) — Rust viene utilizzato per i componenti Bluetooth (ava), DNS-over-HTTP3 e CriticalNotification. Secondo Google (2025), Rust in Android ha eliminato il 70% delle vulnerabilità di memoria nei componenti target.
Per Android si utilizza cargo-ndk, che incapsula Cargo con il toolchain corretto per l'ABI scelto. La build per Android include: aarch64-linux-android (ARM 64-bit, dispositivi moderni), armv7-linux-androideabi (ARM 32-bit), x86_64-linux-android (emulatori).
// Cargo.toml — configurazione libreria per Android/iOS
[package]
name = "mobile_crypto"
version = "0.1.0"
[lib]
crate-type = ["staticlib", "cdylib"]
[dependencies]
serde = { version = "1", features = ["derive"] }
libc = "0.2"crate-type: staticlib — per iOS (.a), cdylib — per Android (.so). serde — serializzazione per lo scambio di dati con Kotlin/Swift. libc — tipi compatibili con C per FFI.
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
/// Funzione compatibile C per elaborazione immagini
#[no_mangle]
pub unsafe extern "C" fn process_image(
input: *const u8,
len: usize,
output: *mut u8,
out_len: *mut usize,
) {
let input_slice = std::slice::from_raw_parts(input, len);
let result: Vec<u8> = input_slice.iter()
.map(|b| b ^ 0xFF)
.collect();
let result_len = result.len();
std::ptr::copy_nonoverlapping(result.as_ptr(), output, result_len);
*out_len = result_len;
}#[no_mangle] disabilita il name mangling per un ABI compatibile con C. extern "C" specifica la convenzione di chiamata C. unsafe — un indicatore che la chiamata dall'esterno di Rust non garantisce sicurezza. std::ptr::copy_nonoverlapping copia i byte del risultato nel buffer di output.
Rust è il candidato ideale per SDK multipiattaforma che funzionano su Android e iOS da un'unica base di codice. Aziende come Mozilla (Firefox), Dropbox (sincronizzazione file) e Meta (blockchain Libra) hanno scelto Rust per componenti critici delle loro applicazioni mobili.
Vantaggi delle librerie Rust rispetto al C++: il compilatore garantisce l'assenza di perdite di memoria e race condition nel codice multipiattaforma. Il codice scritto e testato in Rust funziona in modo identico su tutte le piattaforme. Cargo gestisce le dipendenze in modo nativo, senza CMake o vcpkg.
| Libreria/Crate | Scopo |
|---|---|
| tonic | Client/server gRPC in Rust |
| reqwest | Client HTTP con async/await |
| ring | Crittografia (AES, RSA, ECDSA) |
| sqlx | SQLite e PostgreSQL asincroni |
| wasm-bindgen | Integrazione Rust con JavaScript/WASM |
| ndk-glue | Android NativeActivity in Rust |
| uniffi | Generazione di binding FFI per Kotlin/Swift |
Rust compila in WebAssembly (Wasm) — un formato binario eseguibile nel browser e sui dispositivi mobili. Wasm offre prestazioni quasi native nell'ambiente web. Nello sviluppo mobile, Wasm viene utilizzato in applicazioni ibride (WebView + Wasm) per calcoli complessi: rendering 3D, riconoscimento immagini, crittografia.
wasm-pack compila Rust in .wasm e genera un wrapper JS. wasm-bindgen collega le funzioni Rust con le chiamate JavaScript. Su un dispositivo mobile, l'esecutore Wasm può funzionare in WebView o tramite l'SDK Wasmer/Wasmtime.
use wasm_bindgen::prelude::*;
/// Calcolo dei numeri di Fibonacci in Wasm (chiamato da JS)
#[wasm_bindgen]
pub fn fibonacci(n: u32) -> u64 {
match n {
0 => 0,
1 => 1,
_ => {
let mut a = 0;
let mut b = 1;
for _ in 2..=n {
let temp = a + b;
a = b;
b = temp;
}
b
}
}
}#[wasm_bindgen] genera un wrapper JavaScript per la funzione fibonacci. Nel browser, la chiamata appare come wasm.fibonacci(10). I tipi u32/u64 vengono automaticamente convertiti in Number/BigInt. Il modulo Wasm pesa solo ~5 KB per una tale funzione — overhead minimo.
FFI (Foreign Function Interface) — un meccanismo per chiamare codice Rust da altri linguaggi. Le funzioni Rust con extern "C" e #[no_mangle] vengono esportate con un ABI compatibile con C. Da Kotlin, queste funzioni vengono chiamate tramite JNI, da Swift — tramite @_cdecl ("name") o CBridge.h.
UniFFI — uno strumento Mozilla per generare binding FFI. Si descrive l'API in un file .udl e UniFFI genera automaticamente wrapper Kotlin e Swift. Questo è l'approccio standard per i componenti Rust in Firefox Android e Firefox iOS.
// Libreria Rust con interfaccia UniFFI
uniffi::setup_scaffolding!();
#[derive(uniffi::Enum)]
pub enum EncryptionError {
InvalidKey,
EncryptionFailed,
}
#[derive(uniffi::Record)]
pub struct EncryptedData {
pub ciphertext: Vec<u8>,
pub nonce: Vec<u8>,
}
#[uniffi::export]
pub fn encrypt(key: &[u8], plaintext: &[u8]) -> Result<EncryptedData, EncryptionError> {
// implementazione AES-256-GCM
todo!()
}UniFFI genera una classe Kotlin con il metodo encrypt, che accetta un ByteArray e restituisce EncryptedData. In Swift, viene creata una struct EncryptedData con i campi ciphertext (Data) e nonce (Data). Gli errori vengono convertiti in eccezioni Kotlin/Swift.
Rust e C++ sono i due principali linguaggi per la programmazione di sistema nello sviluppo mobile. Entrambi compilano in codice nativo ARM e supportano FFI tramite l'ABI C. La differenza principale è il modello di sicurezza della memoria: Rust lo verifica in fase di compilazione, C++ si affida alla disciplina dello sviluppatore.
| Criterio | Rust | C++ |
|---|---|---|
| Sicurezza memoria | Garantita (ownership) | Responsabilità sviluppatore |
| Garbage collector | No (RAII + ownership) | No (gestione manuale) |
| Perdite memoria | Prevenute dal compilatore | Possibili (new senza delete) |
| Race condition | Prevenute (Send + Sync) | Possibili |
| Android NDK | Tramite cargo-ndk | Tramite CMake / NDK Build |
| Supporto iOS | cargo-lipo + .a | Xcode + .a |
| Sistema di build | Cargo (integrato) | CMake / Ninja |
| Tempo di build | 2–5 min (pulito) | 5–15 min (pulito) |
| Ecosistema | crates.io (200k+ crate) | vcpkg / Conan (100k+ librerie) |
Rust è più sicuro del C++ e più produttivo — il compilatore cattura errori che in C++ si manifesterebbero a runtime. Il C++ ha un ecosistema di librerie mobili più ricco. Per i nuovi progetti, Rust è preferibile; il codice C++ esistente viene portato gradualmente.
Domande frequenti
La differenza principale è la sicurezza della memoria in fase di compilazione. Rust non ha nullptr, puntatori pendenti o race condition grazie al suo sistema di ownership e borrow checker. Il C++ si affida alla disciplina dello sviluppatore, Rust si affida ai controlli del compilatore.
Sì, tramite Android NDK. Google supporta ufficialmente Rust in AOSP (Android Open Source Project). Rust compila in librerie .so tramite cargo-ndk. FFI (Foreign Function Interface) tramite JNI funziona come per il C++.
Cargo è il gestore di pacchetti e il sistema di build di Rust. Scarica le dipendenze da crates.io, compila il progetto ed esegue i test. Nello sviluppo mobile, cargo-ndk estende Cargo per la cross-compilazione verso ABI Android.
Rust supporta entrambe le piattaforme. Per iOS, cargo-lipo viene utilizzato per creare binari universali (arm64 + x86_64 simulatore). Il codice Rust compila in una libreria statica .a e viene linkato tramite Xcode.
Sì, Rust sta diventando lo standard per SDK multipiattaforma e moduli nativi. Google, Meta e Mozilla stanno investendo in Rust. Per i componenti critici per le prestazioni, Rust è più sicuro e produttivo del C++.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche