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?
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?
Antworten:
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.
[u8; N]
.
Rc<str>
und können Arc<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 ein char*
(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önnen std::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 den String
verwalteten Speicher kopieren :
let a: String = "hello rust".into();
Mit dem folgenden Code können Sie das Literal selbst ohne Kopie verwenden (schreibgeschützt).
let a: &str = "hello rust";
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.
~str
jetztBox<str>
~str
es anbaubar war, während Box<str>
es nicht anbaubar ist. (Das ~str
und ~[T]
waren magisch anbaubar, im Gegensatz zu jedem anderen ~
Objekt, war genau der Grund String
und Vec<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 der str
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. A str
ist konzeptionell nur eine Reihe von u8
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 einen str
wie Box<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 a String
(aber nicht an a &String
). A &str
ist zwei Wörter; Ein Zeiger auf das erste Byte von a str
und eine andere Zahl, die beschreibt, wie viele Bytes das str
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önnen str
, 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 des str
Puffers auf dem Heap ist, immer auf dem Heap (a str
ist nicht unbedingt auf dem Heap), den er verwaltet, bevor er gefüllt wird und neu zugewiesen werden muss. das besitzt im String
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 ein str
und seine Laufzeitdarstellung ist das gleiche wie ein, &str
aber es besitzt auch das andere str
als das, &str
aber es kann seine Größe nicht ändern, da es seine Kapazität nicht kennt, so dass a im Grunde genommen Box<str>
als eine feste Länge angesehen werden String
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]
und Vec<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 es str
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, a String
besitzt das str
auf dem Heap, das es verwaltet, und wenn Sie nur einen Teilstring von a String
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:
let string: String = "a string".to_string();
let substring1: &str = &string[1..3];
let substring2: &str = &string[2..4];
Wir haben zwei verschiedene Teilzeichenfolgen str
derselben Zeichenfolge. string
ist derjenige, der den tatsächlichen vollen str
Puffer auf dem Heap besitzt und die &str
Teilzeichenfolgen sind nur fette Zeiger auf diesen Puffer auf dem Heap.
std::String
ist einfach ein Vektor von u8
. Sie finden die Definition im Quellcode . Es ist haufenweise zugewiesen und kann angebaut werden.
#[derive(PartialOrd, Eq, Ord)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct String {
vec: Vec<u8>,
}
str
ist ein primitiver Typ, auch genannt String Slice genannt . Ein String-Slice hat eine feste Größe. Eine Literalzeichenfolge wie let test = "hello world"
hat &'static str
Typ. test
ist ein Verweis auf diese statisch zugewiesene Zeichenfolge.
&str
kann zum Beispiel nicht geändert werden
let mut word = "hello world";
word[0] = 's';
word.push('\n');
str
hat veränderbare Schicht &mut str
, zum Beispiel:
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);
Eine kleine Änderung an UTF-8 kann jedoch die Bytelänge ändern, und ein Slice kann seinen Referenten nicht neu zuweisen.
In einfachen Worten, String
ist der Datentyp auf dem Heap gespeichert (genau wie Vec
), und Sie haben Zugriff auf diesen Speicherort.
&str
ist ein Slice-Typ. Das heißt, es ist nur ein Hinweis auf eine bereits String
irgendwo auf dem Haufen vorhandene.
&str
führt zur Laufzeit keine Zuordnung durch. Aus Speichergründen können Sie also &str
over verwenden String
. Beachten Sie jedoch, dass Sie sich bei der Verwendung &str
möglicherweise mit expliziten Lebensdauern auseinandersetzen müssen.
str
das view
schon String
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.
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 nur str
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.
&str
besteht aus zwei Komponenten: einem Zeiger auf einige Bytes und einer Länge."