Ce face String
În Rust există două tipuri principale pentru text. String este textul pe care îl deții: stă pe heap, se poate modifica (push_str, insert, clear) și este eliberat automat când variabila iese din domeniu. &str (citește „string slice”) este doar o privire împrumutată spre un text care stă în altă parte: într-un String, în codul programului (literalii "Iași" au tipul &'static str) sau într-un fișier citit în memorie.
Regula practică: în structuri și când construiești text nou folosești String; ca parametru de funcție care doar citește textul folosești &str. Un &String se transformă automat în &str (prin Deref), deci funcția fn salut(nume: &str) primește și &oras, și "Cluj".
Textul este păstrat întotdeauna ca UTF-8. Literele obișnuite ocupă 1 octet, dar ă, â, î, ș, ț ocupă 2 octeți. De aceea len() numără octeți, nu litere, iar indexarea s[0] nu este permisă: compilatorul nu poate ști dacă poziția cade la mijlocul unei litere. Pentru litere folosești chars(), pentru bucăți folosești intervale de octeți &s[0..3] sau metoda sigură get.
Parametri
| Parametru | Descriere |
|---|---|
String |
Text deținut, modificabil, pe heap. Se creează cu String::new(), String::from(...), to_string(), format!. |
&str |
Referință (împrumut) la un text UTF-8 existent. Nu se poate modifica și nu deține memoria. |
Ce returnează
Un obiect String. Metodele lui (push_str, len, chars etc.) au pagini separate; toate metodele lui &str se pot apela și pe un String.
Exemple
Exemplul 1: String și &str în aceeași funcție
Funcția primește &str, deci acceptă atât un literal, cât și un String împrumutat cu &.
fn salut(nume: &str) -> String {
format!("Bună, {nume}!")
}
fn main() {
let literal: &str = "Ana"; // text din codul programului
let mut deținut = String::from("Mihai"); // text care ne aparține
deținut.push_str(" Popescu"); // îl putem modifica
println!("{}", salut(literal));
println!("{}", salut(&deținut)); // &String devine &str automat
println!("{}", salut("Ioana"));
}
Rezultat
Bună, Ana!
Bună, Mihai Popescu!
Bună, Ioana!
Exemplul 2: Octeți, litere și diacritice
Numele are 6 litere, dar 7 octeți, pentru că Ș ocupă 2 octeți în UTF-8. chars().count() numără literele.
fn main() {
let nume = String::from("Ștefan");
println!("octeți (len): {}", nume.len());
println!("caractere (chars): {}", nume.chars().count());
println!("primul caracter: {:?}", nume.chars().next());
println!("al treilea caracter: {:?}", nume.chars().nth(2));
println!("primii 2 octeți: {}", &nume[0..2]); // exact litera Ș
}
Rezultat
octeți (len): 7
caractere (chars): 6
primul caracter: Some('Ș')
al treilea caracter: Some('e')
primii 2 octeți: Ș
Exemplul 3: De ce nu merge oras[0]
Indexarea cu un singur număr nu compilează pentru texte. Mesajul real al compilatorului îți sugerează alternativele: .chars().nth() sau .bytes().nth().
fn main() {
let oras = String::from("Iași");
let prima = oras[0];
println!("{prima}");
}
Eroarea de compilare (rustc)
error[E0277]: the type `str` cannot be indexed by `{integer}`
--> main.rs:3:22
|
3 | let prima = oras[0];
| ^ string indices are ranges of `usize`
|
= help: the trait `SliceIndex<str>` is not implemented for `{integer}`
= note: you can use `.chars().nth()` or `.bytes().nth()`
= note: required for `String` to implement `Index<{integer}>`
Greșeli frecvente
- Scrii
s[0]ca în alte limbaje. Rust nu permite: foloseștes.chars().next()pentru prima literă saus.as_bytes()[0]pentru primul octet. - Tai un text cu un interval care cade în mijlocul unei litere:
&"Iași"[0..3]oprește programul cu panică (byte index 3 is not a char boundary; it is inside 'ș'). Foloseșteget(0..3), care returneazăNoneîn loc de panică. - Scrii
fn f(s: &String). Merge, dar&streste mai flexibil: acceptă și literali, și bucăți de text. - Concatenezi cu
s1 + s2și te miri de eroare. Operatorul+cere în stânga unString(pe care îl consumă) și în dreapta un&str:s1 + &s2. De obiceiformat!("{s1}{s2}")este mai clar.
Comenzi înrudite
str: Tipul pentru o bucată de text UTF-8 împrumutată (&str): literalii, părți din String, parametrii de funcții.String::from: Creează un String nou (deținut) din &str, char sau alt text, copiind conținutul pe heap.String::len: Lungimea textului în OCTEȚI (nu în litere) și verificarea dacă textul e gol. Pentru litere: chars().count().str::chars: Parcurge textul caracter cu caracter (char Unicode), nu octet cu octet. Cu count() afli numărul de litere.char: Un singur caracter Unicode, scris între apostrofuri (‘ș’); ocupă mereu 4 octeți în memorie.str::get: Taie textul sigur: get(a..b) returnează None în loc de panică; is_char_boundary verifică o poziție.