Strumenti Utente

Strumenti Sito


programmazione:rust:appunti_sparsi

Differenze

Queste sono le differenze tra la revisione selezionata e la versione attuale della pagina.

Link a questa pagina di confronto

Entrambe le parti precedenti la revisioneRevisione precedente
Prossima revisione
Revisione precedente
programmazione:rust:appunti_sparsi [08/04/2026 11:33] – Fabio Di Matteoprogrammazione:rust:appunti_sparsi [30/05/2026 15:51] (versione attuale) – [Funzioni async con tokio] Fabio Di Matteo
Linea 2: Linea 2:
 Autore: **//Fabio Di Matteo//** \\ Ultima revisione:  **//  05/04/2026 19:24   //**  // // Autore: **//Fabio Di Matteo//** \\ Ultima revisione:  **//  05/04/2026 19:24   //**  // //
  
-Provenendo da altri linguaggi ho avuto qualche difficoltà ad abituarmi alla sintassi e buone pratiche incoraggiate dal Rust. Metto qualche appunto.+Provenendo da altri linguaggi ho avuto qualche difficoltà ad abituarmi alla sintassi e buone pratiche incoraggiate dal Rust. Metto qualche appunto. Appunti veloci, piu' che altro per uso personale. Il Rust va imparato sul libro. 
 + 
 +===== Libri ===== 
 +[[https://nixxo.github.io/rust-lang-book-it/|Libro in italiano]] 
 +[[https://play.rust-lang.org/|Playground per fare pratica]]
  
 ===== Blocco try/catch ===== ===== Blocco try/catch =====
Linea 60: Linea 64:
 } }
 </code> </code>
 +<note>**.into()** In poche parole prende un valore di un tipo e lo converte in un altro tipo, se esiste una conversione definita (tramite i trait From/Into). Qui prende &str e lo converte in String. 
 +</note>
  
  
Linea 87: Linea 92:
 </code> </code>
  
- N.B. **.into()** In poche parole prende un valore di un tipo e lo converte in un altro tipo, se esiste una conversione definita (tramite i trait From/Into). + 
  
 ==== Con un semplice if ==== ==== Con un semplice if ====
Linea 160: Linea 164:
 assicurandoci prima di aver installato il target in sopraindicato. assicurandoci prima di aver installato il target in sopraindicato.
  
 +
 +===== Le classi =====
 +Un esempio minimo.
 +<code rust>
 +struct Persona {
 +    id: i16,
 +    name: String,
 +    surname: String,
 +}
 +
 +impl Persona {
 +    fn new() -> Self {
 +        return Self {
 +            id: 0,
 +            name: "".into(),
 +            surname: "".into(),
 +        };
 +    }
 +    fn set(&mut self, id: i16, name: String, surname: String) {
 +        self.id = id;
 +        self.name = name;
 +        self.surname = surname;
 +    }
 +}
 +
 +fn main() {
 +    let mut p = Persona::new();
 +    p.set(1, "Fabio".into(), "Di Matteo".into());
 +
 +    println!("{} {} {}", p.id, p.name, p.surname);
 +}
 +
 +
 +</code>
 +Versione con l'aggiunta di un metodo "getter":
 +
 +<code rust>
 +struct Persona {
 +    id: i16,
 +    name: String,
 +    surname: String,
 +}
 +
 +impl Persona {
 +    fn new() -> Self {
 +        return Self {
 +            id: 0,
 +            name: "".into(),
 +            surname: "".into(),
 +        };
 +    }
 +    fn set(&mut self, id: i16, name: String, surname: String) {
 +        self.id = id;
 +        self.name = name;
 +        self.surname = surname;
 +    }
 +
 +    fn get(&self, op: String) -> String {
 +        if op == "name" {
 +            return self.name.clone();
 +        } else if op == "surname" {
 +            return self.surname.clone();
 +        } else {
 +            return self.id.to_string();
 +        }
 +    }
 +}
 +
 +fn main() {
 +    let mut p = Persona::new();
 +    p.set(1, "Fabio".into(), "Di Matteo".into());
 +    let nome = p.get("name".into());
 +    let cognome = p.get("surname".into());
 +    let id = p.get("id".into());
 +
 +    println!("{} {} {}", id, nome, cognome);
 +}
 +
 +</code>
 +
 +===== Sviluppo di programmi dotatati di gui =====
 +Di seguito le mmie esperienze:
 +
 +  * [[programmazione:rust:gtk4_windows|Gtk-rs su windows]]
 +  * [[programmazione:rust:gtkrs:gestione_memoria|Appunti sulla gestione della memoria in Gtkrs e Rust]]
 +  * [[https://www.freemedialab.org/code/project.php?p=video_cutter|Progetto Gtkrs completo di esempio ]]
 +
 +===== I thread =====
 +thread::spawn() lancia direttamente il thread;
 +
 +<code Rust>
 +let t = thread::spawn(|| {
 +        for i in 1..100 {
 +            println!("ciao numero {i} dal thread generato!");
 +            thread::sleep(Duration::from_secs(1));
 +        }
 +    });
 +
 +</code>
 +
 +Aspettare la fine del thread:
 +<code rust>
 +t.join().unwrap();
 +
 +</code>
 +
 +Condivide valori tra thread tramite riferimento grazie ad Arc:
 +<code rust>
 +use std::sync::Arc;
 +use std::thread;
 +
 +let value = Arc::new(vec![1,2,3]);
 +let v1 = Arc::clone(&value);
 +let handle = thread::spawn(move || {
 +    println!("{:?}", v1);
 +});
 +println!("{:?}", value);
 +handle.join().unwrap();
 +
 +</code>
 +
 +La condivisione è sicura. Potremmo anche condividere **mpsc::channel** per usare nei vari thread il contenuto magari di un canale str o altro.
 +
 +
 +===== Funzioni async con tokio =====
 +Eseguire funzioni che richiedono tempo con il runtime tokio:
 +<code rust>
 +use tokio::time::{Duration, sleep};
 +
 +async fn asincrona() {
 +    sleep(Duration::from_millis(3000)).await;
 +    println!("Ciao dalla asincrona!");
 +}
 +
 +#[tokio::main]
 +async fn main() {
 +    // Avvio una funzione async con tokio e passo il controllo
 +    // alle istruzioni successive
 +    tokio::spawn(async { asincrona().await });
 +
 +    println!("Scrivo dal main");
 +    sleep(Duration::from_millis(5000)).await;
 +}
 +
 +</code>
 +
 +Aspettiamo che una funzione,lanciata da tokio precedentemente, finisca del lavoro "lento" per poi continuare il flusso del programma principale.
 +
 +<code rust>
 +use tokio::time::{Duration, sleep};
 +
 +async fn asincrona() -> i32 {
 +    sleep(Duration::from_millis(6000)).await;
 +    println!("Ciao dalla asincrona!");
 +    return 6000;
 +}
 +
 +#[tokio::main]
 +async fn main() {
 +    // Avvio una funzione async con tokio e passo il controllo
 +    // alle istruzioni successive.
 +    let r = tokio::spawn(async { asincrona().await });
 +
 +    // Scrivo qualcosa dal main e dopo un secondo il programma dovrebbe terminare
 +    // Invece no! Aspetto il valore di "r" proveniente dalla funzione async con
 +    // r.await
 +    println!("Scrivo dal main");
 +    sleep(Duration::from_millis(1000)).await;
 +
 +    // Ora che il valore di "r" è disponibile lo stampo se tutto è andato bene,
 +    // oppure stampo "0"
 +    println!(
 +        "Ho aspettato il valore di r {}",
 +        r.await.unwrap_or_else(|_| 0)
 +    );
 +}
 +
 +
 +</code>
 +
 +===== Comunicare con le funzioni async =====
 +<code rust>
 +use std::sync::mpsc;
 +use tokio::time::{Duration, sleep};
 +
 +async fn asincrona(t: mpsc::Sender<&str>) {
 +    loop {
 +        t.send("Ciao dalla fn async!").unwrap();
 +        sleep(Duration::from_millis(2000)).await;
 +    }
 +}
 +
 +#[tokio::main]
 +async fn main() {
 +    let (tx, rx) = mpsc::channel::<&str>();
 +
 +    let tx_clone = tx.clone();
 +    tokio::spawn(async { asincrona(tx_clone).await });
 +
 +    // Un loop che riceve messaggi dalla funzione asincrona e
 +    // li stampa a video.
 +    loop {
 +        sleep(Duration::from_millis(500)).await;
 +        let val = rx.recv().unwrap_or_else(|_| "Niente.");
 +        println!("Ricevo: {}", val)
 +    }
 +}
 +
 +</code>
 +
 +
 +
 +===== Websocket =====
 +Un piccolo esempio di server websocket che aspetta un pacchetto json e lo elabora. Ecco la struttura del json:
 +
 +<code json>
 +{"name":"miafunzione", "params" :"param1,param2,param3"}
 +</code>
 +
 +<code rust>
 +use std::net::TcpListener;
 +use std::thread::spawn;
 +use tungstenite::accept;
 +use serde::{Deserialize, Serialize};
 +use serde_json::Result;
 +//use serde_json::Error;
 +
 +
 +#[derive(Serialize, Deserialize, Debug)]
 +struct Action{
 + name : String,
 + params: String,
 +}
 +
 +
 +fn parse_json(json_str: &str) -> Result<Action> {
 + serde_json::from_str(json_str)
 +}
 +
 +
 +fn handle(j: String) -> String {
 +
 + let a : Action;
 + if  let Err(a) = parse_json(j.as_str()) {
 + drop(a);
 +     "0".to_string()
 + } else {
 + a=parse_json(j.as_str()).unwrap();
 +
 + //For example return my "action" name. 
 + a.name
 + }
 +}
 +
 +fn main() {
 +    let server = TcpListener::bind("127.0.0.1:9001").unwrap();
 +    for stream in server.incoming() {
 +        spawn(move || {
 +            let mut websocket = accept(stream.unwrap()).unwrap();
 +            loop {
 + if let Ok(msg) = websocket.read(){
 + if msg.is_binary() || msg.is_text() {
 +
 + if let Err(e) = websocket.send(handle(msg.to_string()).into()){
 + eprintln!("Error on send to client!");
 + drop(e);
 + }
 +                     
 +                 }
 + }
 +                
 +            }
 +        });
 +    }
 +}
 +
 +</code>
 +
 +**Cargo.toml**
 +<code toml>
 +[package]
 +name = "pobview_backend"
 +version = "0.1.0"
 +edition = "2024"
 +
 +[dependencies]
 +tungstenite = "0.29.0"
 +serde = { version = "1.0", features = ["derive"] }
 +serde_json = "1.0"
 +
 +</code>
 +
 +
 +===== Ottenere directory eseguibile =====
 +<code rust>
 +use std::{env, io, path::PathBuf};
 +
 +fn exe_dir() -> Result<PathBuf, io::Error> {
 +    let exe = env::current_exe()?;
 +    match exe.parent() {
 +        Some(p) => Ok(p.to_path_buf()),
 +        None => Err(io::Error::new(
 +            io::ErrorKind::Other,
 +            "no parent directory for executable",
 +        )),
 +    }
 +}
 +
 +fn main() {
 +    // Utilizzarla senza controllo errori così:
 +    // let myexe_path = exe_dir();
 +    // println!(
 +    //     "Il percorso del mio eseguibile: {}",
 +    //     myexe_path.unwrap().display().to_string()
 +    // );
 +
 +    let myexe_path = exe_dir();
 +    match myexe_path {
 +        Ok(p) => {
 +            println!(
 +                "Il percorso del mio eseguibile è {}",
 +                p.display().to_string()
 +            );
 +        }
 +        Err(e) => {
 +            eprintln!("Problemi nel ricavare il percorso:{} ", e)
 +        }
 +    }
 +}
 +
 +</code>
programmazione/rust/appunti_sparsi.1775640806.txt.gz · Ultima modifica: 08/04/2026 11:33 da Fabio Di Matteo