Le slice in Rust

Le slice in Rust

Le slice sono un tipo di riferimento usato per lavorare su singole porzioni di elementi vicini appartenenti alla stessa collezione. In Rust possiamo fare riferimento a parole contenute in una stringa o valori dentro qualsiasi tipo di collezioni come gli array.

In Rust le slice sono immutabili, perciò possiamo creare tutti i riferimenti che vogliamo senza violare le regole di borrowing. Questo perché il valore originale non può essere modificato.

Esempi di slice in Rust

Iniziamo creando delle istruzioni in main per separare le parole di un testo e conservarle in diverse variabili.

fn main() {
    let my_string = String::from("Hello World");

    let first_word = &my_string[..6]; //Dall'inizio a 5
    let second_word = &my_string[6..]; //Da 6 alla fine

    println!("First word: {}", first_word);
    println!("Second word: {}", second_word);
}

Possiamo anche creare una funzione che accetta come argomento un riferimento al tipo str, lo converte in byte e che ogni volta trova uno spazio, prende i byte dei caratteri precedenti, li converte in str e li ritorna

fn main() {
    let my_string = String::from("Hello World");

    let first_word = extract_word(&my_string[..6]); 
    let second_word = extract_word(&my_string[6..]); 

    println!("First word: {}", first_word);
    println!("Second word: {}", second_word);
}

fn extract_word(slice: &str) -> &str {
    //Converts a string slice to a byte slice and save in a let
    let bytes = slice.as_bytes();

    for (i,&item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &slice[0..i];
        }
    }

    //If there aren't more a word return entire slice
    &slice[..]
}

Esercizio

Possiamo usare questa funzione per separare le parole di un testo. Nell’esempio sotto avremo un errore: la terza parola non esiste perché superiamo l’indice massimo della stringa. Perciò il programma non verrà compilato.

fn main() {
    let my_string = String::from("Hello World");
    let mut len;

    let first_word = extract_word(&my_string); 
    len = first_word.len() + 1;

    let second_word = extract_word(&my_string[len..]); 
    len = len + second_word.len() +1;

    let third_word = extract_word(&my_string[len..]);

    println!("First word: {}", first_word);
    println!("Second word: {}", second_word);
    //Error: len > my_string.len()
    println!("Third word: {}", third_word);
}

thread 'main' panicked at examples/slice.rs:11:45:
byte index 12 is out of bounds of `Hello World`

Possiamo ottimizzare questo codice creando una logica che verifica se superiamo l’indice. Creiamo tre variabili: la stringa da gestire, una per la lunghezza della stringa e un’altra che calcola la lunghezza raggiunta.

Creiamo poi un ciclo che verifica se la lunghezza raggiunta è minore di quella della frase.

  • Se è vero, creiamo una variabile per la nuova parola e sommiamo la sua lunghezza a quella raggiunta + 1 per lo spazio.
  • Se è falso, usciamo dal programma o dalla funzione.

La soluzione si trova alla fine del video in basso.

fn main() {
    let my_string = String::from("Hello World");
    let max_len = my_string.len();
    let mut len= 0;

    crea il ciclo
}