str în Rust

Tipul pentru o bucată de text UTF-8 împrumutată (&str): literalii, părți din String, parametrii de funcții.

Sintaxă
let literal: &'static str = "Iași";
let felie: &str = &text[inceput..sfarsit];   // poziții în octeți

Ce face str

str este „textul în sine”: o secvență de octeți UTF-8 validă. Aproape întotdeauna îl vezi prin referință, ca &str (numit string slice): un pointer spre primul octet și o lungime. Un &str nu deține memoria și nu poate modifica textul; doar îl privește.

Literalii de text din cod au tipul &'static str, pentru că sunt păstrați în programul compilat și trăiesc cât programul. O bucată dintr-un String se obține cu un interval de octeți: &s[0..5], &s[6..]. Capetele trebuie să fie la începutul unui caracter, altfel apare panică. Indexarea cu un singur număr (s[0]) nu există pentru texte.

Toate metodele de citire a textului (len, chars, split, find, trim, replace, parse etc.) sunt definite pe str. Un String le primește automat, prin Deref. Metodele care ar schimba lungimea textului returnează un String nou (replace, to_uppercase) sau un nou &str mai scurt (trim).

Parametri

Parametru Descriere
&'static str Text care trăiește tot programul (literalii).
&str Text împrumutat; compilatorul verifică să nu fie folosit după ce sursa dispare.
&s[a..b] Bucata dintre octeții a (inclusiv) și b (exclusiv).

Ce returnează

Un &str nu este creat de o funcție anume: îl obții dintr-un literal, din &String sau prin tăiere cu un interval.

Exemple

Exemplul 1: Felii dintr-un text

Pozițiile sunt în octeți. „Cluj-Napoca” are doar litere ASCII, deci octeții coincid cu literele.

fn main() {
    let oras = String::from("Cluj-Napoca");
    let primul: &str = &oras[0..4];
    let al_doilea: &str = &oras[5..];
    println!("{primul} | {al_doilea} | {}", &oras[..]);
}

Rezultat

Cluj | Napoca | Cluj-Napoca

Exemplul 2: O funcție care returnează o bucată din parametru

Rezultatul este o privire în textul primit, fără copiere. Compilatorul leagă automat durata de viață a rezultatului de cea a parametrului.

fn primul_cuvant(text: &str) -> &str {
    match text.find(' ') {
        Some(poz) => &text[..poz],
        None => text,
    }
}

fn main() {
    let propozitie = String::from("Ștefan merge la Suceava");
    println!("{}", primul_cuvant(&propozitie));
    println!("{}", primul_cuvant("Galați"));
}

Rezultat

Ștefan
Galați

Exemplul 3: Tăiere în mijlocul unei litere

ș ocupă octeții 2 și 3. Intervalul 0..3 se termină în mijlocul lui, iar programul se oprește. Mesajul de panică spune exact unde.

fn main() {
    let oras = "Iași";
    let bucata = &oras[0..3];
    println!("{bucata}");
}

Rezultat (programul se oprește cu panică)

thread 'main' panicked at main.rs:3:23:
end byte index 3 is not a char boundary; it is inside 'ș' (bytes 2..4 of string)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Greșeli frecvente

  • Încerci să modifici un &str (push_str pe un literal). Un &str este doar citire; transformă-l în String cu to_string().
  • Returnezi dintr-o funcție un &str spre un String creat în funcție: returns a value referencing data owned by the current function. Returnează String.
  • Tai textul cu poziții calculate în litere. Pozițiile din intervale sunt în octeți; folosește char_indices sau get.

Comenzi înrudite

  • String: Textul care îți aparține și se poate modifica: UTF-8, pe heap, crește singur. Diferența față de &str.
  • str::get: Taie textul sigur: get(a..b) returnează None în loc de panică; is_char_boundary verifică o poziție.
  • str::chars: Parcurge textul caracter cu caracter (char Unicode), nu octet cu octet. Cu count() afli numărul de litere.
  • String::len: Lungimea textului în OCTEȚI (nu în litere) și verificarea dacă textul e gol. Pentru litere: chars().count().
  • String::as_str: Returnează un &str care împrumută tot conținutul String-ului; util la match și unde se cere explicit &str.