Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Rust e gestione dell'input/output

Rust e gestione dell'input/output: come ricevere i dati dell'utente, scrivere sui file e leggere i contenuti dei file
Rust e gestione dell'input/output: come ricevere i dati dell'utente, scrivere sui file e leggere i contenuti dei file
Link copiato negli appunti

In Rust e non solo l'input/output, ovvero la capacità di un programma di emettere dati e riceverne dall'esterno, è spesso un aspetto vincolante affinché questo possa procedere con le proprie elaborazioni. Come in ogni corso di programmazione ne abbiamo già visto un primo esempio sin dall'inizio: la stampa delle stringhe in output. In tale caso abbiamo proceduto con una macro messa a disposizione dal linguaggio, println!, ma adesso è arrivato il momento di entrare nei dettagli per comprendere il funzionamento di tutto questo sottosistema.

L'ambito che approcciamo è estremamente vasto a causa delle varie tipologie di input/output ed i diversi casi d'uso che esistono ma qui ci limiteremo ad una presentazione di orientamento seppure a 360 gradi.

Ricevere dati utente

Un primo caso molto utile per interagire con gli utenti è quello della ricezione di input che si esplicita nel chiedere dati all'utente che risponde in maniera interattiva. Per poter accedere a questo sottosistema facciamo riferimento al modulo std::io nel quale troveremo stdin, il canale dell'input nel sistema. Svolgiamo un rapido esempio per scrivere una semplice applicazione di saluto:

use std::io::stdin;
fn main(){
   let mut nome = String::new();
   println!("Come ti chiami?");
   let _ = stdin().read_line(&mut nome);
   println!("Ciao, {}. Benvenuto!", nome.trim());
}

Una volta importato stdin il sistema resta in attesa di un messaggio in input dell'utente e, non appena lo ottiene, lo legge con read_line. Ecco un esempio di sessione di interazione:

Come ti chiami?
Gianluca
Ciao, Gianluca. Benvenuto!

A parte quanto detto, non c'è null'altro di particolare da segnalare nell'esempio se non l'uso della funzione trim per eliminare dal testo letto il carattere di a capo.

Sebbene potremmo non sentirne il bisogno grazie a println!, ricordiamo che esiste anche un sistema di output con std::io che offre accesso al canale stdout.

Scrivere su file in Rust

Per quanto riguarda la scrittura su file, il percorso non è così differente. Accederemo all'oggetto use std::io::Write che creerà un canale di comunicazione con il file destinazione che sarà definito mediante std::fs::File. Proviamo - anche a titolo di ripasso - a riproporre l'esempio della stampa della tabellina in modo che l'ouput non sia stampato a console ma rediretto su file e che quest'ultimo abbia un nome personalizzato in base alla tabellina stampata. Ovviamente, approfittando di quanto visto nel primo paragrafo di questa lezione, sarà l'utente a scegliere di quale numero stampare la tabellina! Ecco qui:

use std::io::Write;
use std::fs::File;
use std::io::stdin;
fn main() {
   let mut input = String::new();
   println!("Immettere un numero intero:");
   // leggiamo un numero in input
   let _=stdin().read_line(&mut input).expect("Errore di lettura dell'input");
   let tabellina_del:u8=input.trim().parse().expect("Non hai immesso un numero!");
   // definiamo il file destinazione
   let mut file = File::create(format!("tabellina_del_{}.txt", tabellina_del)).expect("Errore: creazione del file non riuscita!");
   for contatore in 1..=10{
      // creiamo una singola riga della tabellina
      let riga= format!("{} X {} = {}\n", tabellina_del, contatore, tabellina_del*contatore);
      // salviamo la riga su file
      file.write_all(riga.as_bytes()).expect("Errore in scrittura");
   }
   println!("Fine del salvataggio del file");
}

Se, ad esempio, alla richiesta Immettere un numero intero: rispondessimo 7 otterremmo il file tabellina_del_7.txt con il seguente contenuto:

7 X 1 = 7
7 X 2 = 14
7 X 3 = 21
7 X 4 = 28
7 X 5 = 35
7 X 6 = 42
7 X 7 = 49
7 X 8 = 56
7 X 9 = 63
7 X 10 = 70

Altro aspetto interessante è la macro format! che si usa per formattare del testo in una nuova stringa usando gli stessi formati di println!.

Leggere da file con Rust

La lettura da file è un argomento più vasto di quanto visto sinora e offre varie possibilità soprattutto in base alle dimensioni del file che potrebbero richiedere approcci ottimizzati. In questo punto, vedremo quello più comune e generalmente utilizzato in moltissimi casi. Con questo approccio Rust offre una certa duttilità in quanto permette di ricevere l'intero contenuto del file in una stringa e da qui iniziare ad analizzarla. Come si può immaginare procederemo in maniera analoga al caso precedente ovvero attingendo al modulo std::io:

use std::io::Read;
fn main(){
   let file = std::fs::File::open("tabellina_del_7.txt").unwrap();
   let mut contenuto = String::new();
   file.read_to_string(&mut contenuto).unwrap();
   print!("{}", contenuto);
}

Il contenuto che verrà prodotto in output sarà quello già considerato prima e, come possiamo vedere, l'intero procedimento è in mano alla funzione read_to_string che si preoccuperà di inserire tutto quello che c'è nel file all'interno della stringa contenuto.

Ti consigliamo anche