Perché Rust ha Stringe str? Quali sono le differenze tra Stringe str? Quando si usa Stringinvece di stre viceversa? Uno di loro viene deprecato?
Perché Rust ha Stringe str? Quali sono le differenze tra Stringe str? Quando si usa Stringinvece di stre viceversa? Uno di loro viene deprecato?
Risposte:
Stringè il tipo di stringa heap dinamico, ad esempio Vec: utilizzalo quando devi possedere o modificare i dati della stringa.
strè una sequenza immutabile di 1 byte UTF-8 di lunghezza dinamica da qualche parte nella memoria. Poiché la dimensione è sconosciuta, è possibile gestirla solo dietro un puntatore. Ciò significa che il strpiù delle volte 2 appare come &str: un riferimento ad alcuni dati UTF-8, normalmente chiamati "slice slice" o semplicemente "slice". Una sezione è solo una vista su alcuni dati e tali dati possono essere ovunque, ad es
"foo"è a &'static str. I dati vengono hardcoded nell'eseguibile e caricati in memoria all'avvio del programma.String : Stringdereferenze a una &strvista dei Stringdati.Sullo stack : ad esempio, quanto segue crea un array di byte allocato nello stack e quindi ottiene una visualizzazione di tali dati come&str :
use std::str;
let x: &[u8] = &[b'a', b'b', b'c'];
let stack_str: &str = str::from_utf8(x).unwrap();
In sintesi, utilizzare Stringse sono necessari dati di stringa di proprietà (come passare stringhe ad altri thread o crearli in fase di esecuzione) e utilizzare &strse è necessaria solo la visualizzazione di una stringa.
Questo è identico alla relazione tra un vettore Vec<T>e una sezione &[T]ed è simile alla relazione tra valore per Te riferimento &Tper i tipi generali.
1 A strè a lunghezza fissa; non è possibile scrivere byte oltre la fine o lasciare byte finali non validi. Poiché UTF-8 è una codifica a larghezza variabile, ciò costringe effettivamente tutti gli strs a essere immutabili in molti casi. In generale, la mutazione richiede la scrittura di un numero maggiore o minore di byte rispetto a prima (ad esempio, la sostituzione di un a(1 byte) con un ä(2+ byte) richiederebbe di creare più spazio nel str). Ci sono metodi specifici che possono modificare un &strposto, soprattutto quelli che gestiscono solo caratteri ASCII, come make_ascii_uppercase.
2 I tipi di dimensioni dinamiche consentono cose come Rc<str>per una sequenza di byte UTF-8 contati di riferimento da Rust 1.2. Rust 1.21 consente di creare facilmente questi tipi.
[u8; N].
Rc<str>e Arc<str>ora sono utilizzabili tramite la libreria standard.
Ho un background C ++ e ho trovato molto utile pensare Stringe &strin termini C ++:
Stringè come una std::string; possiede la memoria e fa il lavoro sporco di gestione della memoria.&strè come una char*(ma un po 'più sofisticata); ci indica l'inizio di un blocco nello stesso modo in cui è possibile ottenere un puntatore al contenuto di std::string.Uno di loro sparirà? Non la penso così. Servono a due scopi:
Stringmantiene il buffer ed è molto pratico da usare. &strè leggero e dovrebbe essere usato per "guardare" nelle stringhe. È possibile cercare, dividere, analizzare e persino sostituire i blocchi senza dover allocare nuova memoria.
&strpuò guardare all'interno di a Stringin quanto può indicare una stringa letterale. Il codice seguente deve copiare la stringa letterale nella Stringmemoria gestita:
let a: String = "hello rust".into();
Il seguente codice ti consente di usare il valore letterale stesso senza copia (leggi solo però)
let a: &str = "hello rust";
str, usato solo come &str, è una porzione di stringa, un riferimento a una matrice di byte UTF-8.
Stringè quello che era ~strun array di byte UTF-8 di proprietà coltivabile.
~stradesso èBox<str>
~strera coltivabile mentre Box<str>non è coltivabile. (Quello ~stred ~[T]erano magicamente coltivabili, a differenza di qualsiasi altro oggetto ~, era esattamente il motivo Stringe Vec<T>furono introdotti, in modo che le regole fossero tutte semplici e coerenti.)
In realtà sono completamente diversi. Prima di tutto, a strnon è altro che una cosa a livello di tipo; può essere ragionato solo a livello di tipo perché è un cosiddetto tipo di dimensioni dinamiche (DST). La dimensione che stroccupa non può essere conosciuta al momento della compilazione e dipende dalle informazioni di runtime - non può essere memorizzata in una variabile perché il compilatore deve sapere in fase di compilazione quale sia la dimensione di ciascuna variabile. A strè concettualmente solo una riga di u8byte con la garanzia che forma UTF-8 valido. Quanto è grande la fila? Nessuno lo sa fino al runtime, quindi non può essere archiviato in una variabile.
La cosa interessante è che una &stro qualsiasi altro puntatore a una strcome Box<str> fa esistere in fase di esecuzione. Questo è un cosiddetto "puntatore grasso"; è un puntatore con informazioni extra (in questo caso la dimensione dell'oggetto a cui punta), quindi è due volte più grande. In effetti, a &strè abbastanza vicino a a String(ma non a a &String). A &strè due parole; un puntatore a un primo byte di un stre un altro numero che descrive quanti byte sono lunghi str.
Contrariamente a quanto detto, a strnon deve essere immutabile. Se riesci a ottenere un &mut strpuntatore esclusivo a str, puoi mutarlo e tutte le funzioni sicure che lo mutano garantiscono che il vincolo UTF-8 sia rispettato perché se viene violato abbiamo un comportamento indefinito poiché la biblioteca presume che questo vincolo sia vero e non lo controlla.
Quindi cos'è un String? Sono tre parole; due sono uguali a &strma aggiunge una terza parola che è la capacità del strbuffer sull'heap, sempre sull'heap (a strnon è necessariamente sull'heap) che gestisce prima di essere riempito e deve riassegnare. il Stringfondo possiede un strcome si dice; lo controlla e può ridimensionarlo e riallocarlo quando lo ritiene opportuno. Quindi a Stringè come detto più vicino a &strche a str.
Un'altra cosa è a Box<str>; anche questo possiede un stre la sua rappresentazione di runtime è la stessa di un &strma possiede anche il strcontrario del &strma non può ridimensionarlo perché non conosce la sua capacità, quindi sostanzialmente Box<str>può essere visto come una lunghezza fissa Stringche non può essere ridimensionata (puoi convertilo sempre in a Stringse vuoi ridimensionarlo).
Esiste una relazione molto simile tra [T]e Vec<T>tranne che non esiste alcun vincolo UTF-8 e può contenere qualsiasi tipo le cui dimensioni non sono dinamiche.
L'uso stra livello di tipo serve principalmente a creare astrazioni generiche con &str; esiste a livello di tipo per poter scrivere comodamente i tratti. In teoria str, una cosa tipo non aveva bisogno di esistere e solo, &strma ciò avrebbe significato scrivere un sacco di codice extra che ora può essere generico.
&strè super utile per poter avere più sottostringhe diverse di a Stringsenza dover copiare; come detto a String possiede l' strheap che gestisce e se si potesse creare solo una sottostringa di a Stringcon una nuova String, sarebbe necessario copiarla perché tutto in Rust può avere un solo proprietario per gestire la sicurezza della memoria. Quindi, ad esempio, puoi tagliare una stringa:
let string: String = "a string".to_string();
let substring1: &str = &string[1..3];
let substring2: &str = &string[2..4];
Abbiamo due sottostringhe diverse strdella stessa stringa. stringè quello che possiede il strbuffer completo effettivo sull'heap e le &strsottostringhe sono solo puntatori di grasso a quel buffer sull'heap.
std::Stringè semplicemente un vettore di u8. Puoi trovarne la definizione nel codice sorgente . È allocato in heap e coltivabile.
#[derive(PartialOrd, Eq, Ord)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct String {
vec: Vec<u8>,
}
strè un tipo primitivo, chiamato anche stringa slice . Una sezione di stringa ha dimensioni fisse. Una stringa letterale come let test = "hello world"ha &'static strtipo. testè un riferimento a questa stringa allocata staticamente.
&strnon può essere modificato, ad esempio,
let mut word = "hello world";
word[0] = 's';
word.push('\n');
strha una sezione mutabile &mut str, ad esempio:
pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str)
let mut s = "Per Martin-Löf".to_string();
{
let (first, last) = s.split_at_mut(3);
first.make_ascii_uppercase();
assert_eq!("PER", first);
assert_eq!(" Martin-Löf", last);
}
assert_eq!("PER Martin-Löf", s);
Ma una piccola modifica a UTF-8 può cambiare la sua lunghezza in byte e una sezione non può riallocare il suo referente.
In parole semplici, il Stringtipo di dati è memorizzato sull'heap (proprio come Vec) e hai accesso a quella posizione.
&strè un tipo di fetta. Ciò significa che è solo un riferimento a un già presente Stringda qualche parte nell'heap.
&strnon esegue alcuna allocazione in fase di esecuzione. Quindi, per ragioni di memoria, è possibile utilizzare &strsopra String. Tuttavia, tieni presente che durante l'utilizzo &strpotresti dover affrontare vite esplicite.
strè viewgià presente Stringnell'heap.
Per persone C # e Java:
String===StringBuilder &str stringa di Rust === (immutabile)Mi piace pensare a &strcome una vista su una stringa, come una stringa internata in Java / C # dove non è possibile cambiarla, ma crearne una nuova.
Ecco una spiegazione semplice e veloce.
String- Una struttura di dati allocabile heap allocabile e coltivabile. Può essere costretto a &str.
str- è (ora, man mano che Rust si evolve) stringa mutabile di lunghezza fissa che vive nell'heap o nel binario. È possibile interagire solo strcome tipo preso in prestito tramite una vista di tipo stringa, ad esempio &str.
Considerazioni sull'uso:
Preferisci Stringse vuoi possedere o mutare una stringa - come passare la stringa a un altro thread, ecc.
Preferisci &strse vuoi avere una vista di sola lettura di una stringa.
&strè composto da due componenti: un puntatore ad alcuni byte e una lunghezza".