Warum hat Rust String
und str
? Was sind die Unterschiede zwischen String
und str
? Wann verwendet man String
statt str
und umgekehrt? Wird einer von ihnen veraltet?
String
ist der dynamische Heap-String-Typ wie Vec
.: Verwenden Sie ihn, wenn Sie Ihre Zeichenfolgendaten besitzen oder ändern müssen.
str
ist eine unveränderliche 1- Sequenz von UTF-8-Bytes mit dynamischer Länge irgendwo im Speicher. Da die Größe unbekannt ist, kann man sie nur hinter einem Zeiger behandeln. Dies bedeutet, dass 2str
am häufigsten als Verweis auf einige UTF-8-Daten angezeigt wird , die normalerweise als "String-Slice" oder nur als "Slice" bezeichnet werden. Ein Slice ist nur eine Ansicht einiger Daten, und diese Daten können sich überall befinden, z&str
"foo"
ist a &'static str
. Die Daten werden fest in die ausführbare Datei codiert und beim Ausführen des Programms in den Speicher geladen.String
: String
Dereferenzen zu einer &str
Ansicht der String
Daten des Daten.Auf dem Stapel : z. B. erstellt das Folgende ein vom Stapel zugewiesenes Byte-Array und erhält dann eine Ansicht dieser Daten als&str
:
use std::str;
let x: &[u8] = &[b'a', b'b', b'c'];
let stack_str: &str = str::from_utf8(x).unwrap();
Zusammenfassend lässt sich sagen, String
ob Sie eigene Zeichenfolgendaten benötigen (z. B. Zeichenfolgen an andere Threads übergeben oder zur Laufzeit erstellen) und verwenden, &str
wenn Sie nur eine Ansicht einer Zeichenfolge benötigen.
Dies ist identisch mit der Beziehung zwischen einem Vektor Vec<T>
und einem Slice &[T]
und ähnelt der Beziehung zwischen By-Value T
und By-Reference &T
für allgemeine Typen.
1 A str
ist feste Länge; Sie können keine Bytes über das Ende hinaus schreiben oder nachfolgende ungültige Bytes belassen. Da UTF-8 eine Codierung mit variabler Breite ist, werden alle str
s in vielen Fällen unveränderlich. Im Allgemeinen erfordert die Mutation das Schreiben von mehr oder weniger Bytes als zuvor (z. B. würde das Ersetzen eines a
(1 Bytes) durch ein ä
(2+ Bytes) mehr Platz im str
) erfordern . Es gibt bestimmte Methoden, mit denen ein &str
Ort geändert werden kann , hauptsächlich solche, die nur ASCII-Zeichen verarbeiten, wie zmake_ascii_uppercase
.
2 Typen mit dynamischer Größe ermöglichen beispielsweise Rc<str>
eine Folge von UTF-8-Bytes mit Referenzzählung seit Rust 1.2. Mit Rust 1.21 können diese Typen einfach erstellt werden.
&str
besteht aus zwei Komponenten: einem Zeiger auf einige Bytes und einer Länge."[u8; N]
.Rc<str>
und könnenArc<str>
jetzt über die Standardbibliothek verwendet werden.Ich habe einen C ++ Hintergrund und ich fand es sehr nützlich , um darüber nachzudenken
String
und&str
in C ++ Bedingungen:String
ist wie einstd::string
; Es besitzt den Speicher und erledigt die schmutzige Arbeit der Speicherverwaltung.&str
ist wie einchar*
(aber etwas raffinierter); Es zeigt uns auf den Anfang eines Blocks auf die gleiche Weise, wie Sie einen Zeiger auf den Inhalt von erhalten könnenstd::string
.Wird einer von ihnen verschwinden? Ich glaube nicht. Sie dienen zwei Zwecken:
String
Hält den Puffer und ist sehr praktisch zu bedienen.&str
ist leicht und sollte verwendet werden, um in Saiten zu "schauen". Sie können Chunks suchen, teilen, analysieren und sogar ersetzen, ohne neuen Speicher zuweisen zu müssen.&str
kann in ein schauen,String
da es auf ein String-Literal verweisen kann. Der folgende Code muss die Literalzeichenfolge in denString
verwalteten Speicher kopieren :Mit dem folgenden Code können Sie das Literal selbst ohne Kopie verwenden (schreibgeschützt).
quelle
str
, wird nur als verwendet&str
, ist ein String-Slice, ein Verweis auf ein UTF-8-Byte-Array.String
war früher~str
ein wachsbares UTF-8-Byte-Array.quelle
~str
jetztBox<str>
~str
es anbaubar war, währendBox<str>
es nicht anbaubar ist. (Das~str
und~[T]
waren magisch anbaubar, im Gegensatz zu jedem anderen~
Objekt, war genau der GrundString
undVec<T>
wurden eingeführt, so dass die Regeln alle einfach und konsistent waren.)Sie sind eigentlich ganz anders. Zunächst einmal
str
ist a nichts anderes als eine Sache auf Typebene; Dies kann nur auf Typebene begründet werden, da es sich um einen sogenannten Typ mit dynamischer Größe (DST) handelt. Die Größe derstr
Aufnahme kann zur Kompilierungszeit nicht bekannt sein und hängt von den Laufzeitinformationen ab. Sie kann nicht in einer Variablen gespeichert werden, da der Compiler zur Kompilierungszeit wissen muss, wie groß jede Variable ist. Astr
ist konzeptionell nur eine Reihe vonu8
Bytes mit der Garantie, dass es gültiges UTF-8 bildet. Wie groß ist die Reihe? Niemand weiß es bis zur Laufzeit, daher kann es nicht in einer Variablen gespeichert werden.Das Interessante daran ist , dass ein
&str
oder andere Zeiger auf einenstr
wieBox<str>
tun exist zur Laufzeit. Dies ist ein sogenannter "Fettzeiger"; Es ist ein Zeiger mit zusätzlichen Informationen (in diesem Fall die Größe des Objekts, auf das es zeigt), also doppelt so groß. In der Tat ist a&str
ziemlich nah an aString
(aber nicht an a&String
). A&str
ist zwei Wörter; Ein Zeiger auf das erste Byte von astr
und eine andere Zahl, die beschreibt, wie viele Bytes dasstr
ist.Im Gegensatz zu dem, was gesagt wird,
str
muss a nicht unveränderlich sein. Wenn Sie einen&mut str
als exklusiven Zeiger auf das erhalten könnenstr
, können Sie ihn mutieren, und alle sicheren Funktionen, die ihn mutieren, garantieren, dass die UTF-8-Einschränkung beibehalten wird. Wenn dies verletzt wird, haben wir ein undefiniertes Verhalten, da die Bibliothek diese Einschränkung annimmt wahr und prüft nicht darauf.Was ist ein
String
? Das sind drei Wörter; zwei sind die gleichen wie für,&str
aber es wird ein drittes Wort hinzugefügt, das die Kapazität desstr
Puffers auf dem Heap ist, immer auf dem Heap (astr
ist nicht unbedingt auf dem Heap), den er verwaltet, bevor er gefüllt wird und neu zugewiesen werden muss. das besitzt imString
Grunde ein wie sie sagen; Es steuert es und kann seine Größe ändern und es neu zuweisen, wenn es dies für richtig hält. Also ist a wie gesagt näher an a als an a .str
String
&str
str
Eine andere Sache ist a
Box<str>
; Dies besitzt auch einstr
und seine Laufzeitdarstellung ist das gleiche wie ein,&str
aber es besitzt auch das anderestr
als das,&str
aber es kann seine Größe nicht ändern, da es seine Kapazität nicht kennt, so dass a im Grunde genommenBox<str>
als eine feste Länge angesehen werdenString
kann, deren Größe nicht geändert werden kann (Sie können konvertieren Sie es immer in ein,String
wenn Sie die Größe ändern möchten).Eine sehr ähnliche Beziehung besteht zwischen
[T]
undVec<T>
außer es gibt keine UTF-8-Einschränkung und sie kann jeden Typ enthalten, dessen Größe nicht dynamisch ist.Die Verwendung
str
auf Typebene dient hauptsächlich dazu, generische Abstraktionen mit zu erstellen&str
. Es existiert auf Typebene, um Merkmale bequem schreiben zu können. Theoretisch musste esstr
als Typ nicht existieren und nur,&str
aber das würde bedeuten, dass viel zusätzlicher Code geschrieben werden müsste, der jetzt generisch sein kann.&str
ist sehr nützlich, um mehrere verschiedene Teilzeichenfolgen von a haben zu können,String
ohne kopieren zu müssen; Wie gesagt, aString
besitzt dasstr
auf dem Heap, das es verwaltet, und wenn Sie nur einen Teilstring von aString
mit einem neuen erstellen könnten,String
müsste dieser kopiert werden, da alles in Rust nur einen einzigen Eigentümer haben kann, der sich mit der Speichersicherheit befasst. So können Sie beispielsweise eine Zeichenfolge in Scheiben schneiden:Wir haben zwei verschiedene Teilzeichenfolgen
str
derselben Zeichenfolge.string
ist derjenige, der den tatsächlichen vollenstr
Puffer auf dem Heap besitzt und die&str
Teilzeichenfolgen sind nur fette Zeiger auf diesen Puffer auf dem Heap.quelle
std::String
ist einfach ein Vektor vonu8
. Sie finden die Definition im Quellcode . Es ist haufenweise zugewiesen und kann angebaut werden.str
ist ein primitiver Typ, auch genannt String Slice genannt . Ein String-Slice hat eine feste Größe. Eine Literalzeichenfolge wielet test = "hello world"
hat&'static str
Typ.test
ist ein Verweis auf diese statisch zugewiesene Zeichenfolge.&str
kann zum Beispiel nicht geändert werdenstr
hat veränderbare Schicht&mut str
, zum Beispiel:pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str)
Eine kleine Änderung an UTF-8 kann jedoch die Bytelänge ändern, und ein Slice kann seinen Referenten nicht neu zuweisen.
quelle
In einfachen Worten,
String
ist der Datentyp auf dem Heap gespeichert (genau wieVec
), und Sie haben Zugriff auf diesen Speicherort.&str
ist ein Slice-Typ. Das heißt, es ist nur ein Hinweis auf eine bereitsString
irgendwo auf dem Haufen vorhandene.&str
führt zur Laufzeit keine Zuordnung durch. Aus Speichergründen können Sie also&str
over verwendenString
. Beachten Sie jedoch, dass Sie sich bei der Verwendung&str
möglicherweise mit expliziten Lebensdauern auseinandersetzen müssen.quelle
str
dasview
schonString
im Haufen vorhanden ist.Für C # - und Java-Benutzer:
String
===StringBuilder
&str
=== (unveränderlicher) StringIch stelle mir eine
&str
als Ansicht einer Zeichenfolge vor, wie eine internierte Zeichenfolge in Java / C #, bei der Sie sie nicht ändern können, sondern nur eine neue erstellen.quelle
Hier ist eine schnelle und einfache Erklärung.
String
- Eine erweiterbare, besitzbare Heap-zugewiesene Datenstruktur. Es kann zu a gezwungen werden&str
.str
- ist (jetzt, da sich Rust weiterentwickelt) eine veränderbare Zeichenfolge mit fester Länge, die auf dem Heap oder in der Binärdatei lebt. Sie können nurstr
als ausgeliehener Typ über eine String-Slice-Ansicht interagieren , z&str
.Überlegungen zur Verwendung:
Ziehen
String
Sie es vor, wenn Sie eine Zeichenfolge besitzen oder mutieren möchten, z. B. die Zeichenfolge an einen anderen Thread übergeben usw.Bevorzugen
&str
Sie, wenn Sie eine schreibgeschützte Ansicht einer Zeichenfolge haben möchten.quelle