Dlaczego Rust ma String
i str
? Jakie są różnice między String
i str
? Kiedy używa się String
zamiast str
i odwrotnie? Czy jeden z nich staje się przestarzały?
String
jest dynamicznym typem łańcucha stosu, takim jak Vec
: użyj go, gdy chcesz posiadać lub zmodyfikować dane łańcucha.
str
to niezmienna 1 sekwencja bajtów UTF-8 o dynamicznej długości gdzieś w pamięci. Ponieważ rozmiar jest nieznany, można go obsługiwać tylko za wskaźnikiem. Oznacza to, że str
najczęściej 2 pojawia się jako &str
: odniesienie do niektórych danych UTF-8, zwykle nazywanych „wycinkiem łańcucha” lub po prostu „wycinkiem”. Wycinek to tylko widok niektórych danych, które mogą znajdować się w dowolnym miejscu, np
"foo"
to &'static str
. Dane są zakodowane na stałe w pliku wykonywalnym i ładowane do pamięci podczas działania programu.String
: String
dereferences do &str
widoku z String
danych „s.Na stosie : np. Następujące tworzy tablicę bajtów przydzieloną do stosu, a następnie wyświetla te dane jako&str
:
use std::str;
let x: &[u8] = &[b'a', b'b', b'c'];
let stack_str: &str = str::from_utf8(x).unwrap();
Podsumowując, użyj, String
jeśli potrzebujesz posiadanych danych ciągów (takich jak przekazywanie ciągów do innych wątków lub budowanie ich w czasie wykonywania), i użyj, &str
jeśli potrzebujesz tylko widoku ciągu.
Jest to identyczne z relacją między wektorem Vec<T>
a wycinkiem &[T]
i jest podobne do relacji między wartością T
a odniesieniem &T
dla typów ogólnych.
1 A str
ma ustaloną długość; nie można pisać bajtów poza końcem ani pozostawiać końcowych niepoprawnych bajtów. Ponieważ UTF-8 jest kodowaniem o zmiennej szerokości, to skutecznie zmusza wszystkie str
s do niezmienności w wielu przypadkach. Ogólnie rzecz biorąc, mutacja wymaga zapisania większej lub mniejszej liczby bajtów niż wcześniej (np. Zastąpienie a
(1 bajtu) przez ä
(2+ bajty) wymagałoby więcej miejsca w str
). Istnieją określone metody, które mogą modyfikować &str
miejsce, głównie te, które obsługują tylko znaki ASCII, takie jak make_ascii_uppercase
.
2 Typy o dynamicznym rozmiarze pozwalają np. Rc<str>
Na sekwencję liczonych referencji bajtów UTF-8 od wersji Rust 1.2. Rdza 1.21 pozwala łatwo tworzyć te typy.
&str
składa się z dwóch komponentów: wskaźnik do niektórych bajtów, a długość”.[u8; N]
.Rc<str>
iArc<str>
można je teraz używać za pomocą standardowej biblioteki.Mam C ++ tła i uważam, że to bardzo przydatna zastanowić
String
i&str
pod względem c ++:String
jest jakstd::string
; jest właścicielem pamięci i wykonuje brudną robotę zarządzania pamięcią.&str
jest jakchar*
(ale trochę bardziej wyrafinowana); wskazuje nam początek fragmentu w taki sam sposób, w jaki można uzyskać wskaźnik do zawartościstd::string
.Czy któreś z nich zniknie? Nie sądzę. Służą one dwóm celom:
String
zachowuje bufor i jest bardzo praktyczny w użyciu.&str
jest lekki i powinien być używany do „przeglądania” ciągów znaków. Możesz wyszukiwać, dzielić, analizować, a nawet zamieniać porcje bez konieczności przydzielania nowej pamięci.&str
może zajrzeć do środka,String
ponieważ może wskazywać na dosłowny ciąg znaków. Poniższy kod musi skopiować literały ciąg doString
pamięci zarządzanej:Poniższy kod pozwala używać samego literału bez kopiowania (tylko do odczytu)
źródło
str
, używany tylko jako&str
, jest ciągiem znaków, odniesieniem do tablicy bajtów UTF-8.String
to~str
dawna, rosnąca, własna tablica bajtów UTF-8.źródło
~str
teraz byłoBox<str>
~str
był uprawiany, podczas gdyBox<str>
nie był uprawiany. (To~str
i~[T]
były magicznie uprawiane, w przeciwieństwie do innych~
obiektów, było dokładnie tego powodemString
iVec<T>
zostały wprowadzone, aby wszystkie zasady były proste i spójne.)W rzeczywistości są zupełnie inne. Po pierwsze, a
str
jest niczym innym, jak tylko poziomem czcionki; można to uzasadnić tylko na poziomie typu, ponieważ jest to tak zwany typ dynamicznie wielkości (DST). Rozmiar, którystr
zajmuje, nie może być znany w czasie kompilacji i zależy od informacji o środowisku wykonawczym - nie można go zapisać w zmiennej, ponieważ kompilator musi wiedzieć w czasie kompilacji, jaki jest rozmiar każdej zmiennej. Astr
jest koncepcyjnie tylko rzędemu8
bajtów z gwarancją, że tworzy poprawny UTF-8. Jak duży jest rząd? Nikt nie wie do czasu uruchomienia, dlatego nie można go zapisać w zmiennej.Interesującą rzeczą jest to, że
&str
albo każdy inny wskaźnik dostr
LikeBox<str>
nie istnieje w czasie wykonywania. Jest to tak zwany „wskaźnik tłuszczu”; jest wskaźnikiem z dodatkowymi informacjami (w tym przypadku wielkości rzeczy, na którą wskazuje), więc jest dwa razy większy. W rzeczywistości a&str
jest dość zbliżone doString
(ale nie do a&String
). A&str
to dwa słowa; jeden wskaźnik do pierwszego bajtustr
ai druga liczba, która opisuje, ile bajtów ma długośćstr
.W przeciwieństwie do tego, co powiedziano, a
str
nie musi być niezmienne. Jeśli możesz uzyskać wskaźnik&mut str
jako wyłącznystr
, możesz go zmutować, a wszystkie bezpieczne funkcje, które go mutują, gwarantują utrzymanie ograniczenia UTF-8, ponieważ jeśli zostanie ono naruszone, wówczas nie zdefiniujemy zachowania, ponieważ biblioteka zakłada, że to ograniczenie jest prawda i nie sprawdza jej.Co to jest
String
? To trzy słowa; dwa są takie same jak dla,&str
ale dodaje trzecie słowo, które jest pojemnościąstr
bufora na stercie, zawsze na stercie (astr
niekoniecznie jest na stercie), którą zarządza zanim zostanie wypełniona i będzie musiała ponownie przydzielić.String
zasadzie posiadastr
jak mówią; kontroluje to i może zmieniać jego rozmiar oraz ponownie przydzielać, kiedy uzna to za stosowne. Tak więc,String
jak powiedziano, bliżej&str
niż dostr
.Inną rzeczą jest
Box<str>
; posiada również a,str
a jego środowisko wykonawcze jest takie samo jak a,&str
ale jest także właścicielem wstr
przeciwieństwie do,&str
ale nie może zmienić jego rozmiaru, ponieważ nie zna swojej pojemności, więc w zasadzieBox<str>
można postrzegać jako stałą długośćString
, której nie można zmienić ( zawsze zamień go naString
jeśli chcesz zmienić jego rozmiar).Istnieje bardzo podobny związek między
[T]
iVec<T>
chyba nie ma ograniczenia UTF-8 i może posiadać dowolny typ, którego rozmiar nie jest dynamiczny.Użycie
str
na poziomie typu służy głównie do tworzenia ogólnych abstrakcji&str
; istnieje na poziomie typu, aby móc wygodnie pisać cechy. Teoretyczniestr
jako typ rzecz nie musiała istnieć i tylko to,&str
ale oznaczałoby to, że trzeba napisać dużo dodatkowego kodu, który może być teraz ogólny.&str
jest bardzo przydatny, aby móc mieć wiele różnych podciągówString
bez konieczności kopiowania; jak powiedziałString
posiadastr
na stercie zarządza, i jeśli można utworzyć tylko podciąg od aString
z nowymString
musiałby skopiowana, ponieważ wszystko w Rust może mieć tylko jeden pojedynczy właściciela do czynienia z bezpieczeństwem pamięci. Na przykład możesz pokroić ciąg:Mamy dwa różne podciągi
str
tego samego łańcucha.string
jest właścicielem rzeczywistego pełnegostr
buforu na stercie, a&str
podłańcuchy są po prostu wskaźnikami tłuszczu do tego buforu na stercie.źródło
std::String
jest po prostu wektoremu8
. Można znaleźć jego definicję w kodzie źródłowym . Jest alokowany na stos i można go uprawiać.str
jest prymitywnym typem, zwanym także wycinkiem łańcucha . Wycinek łańcucha ma ustalony rozmiar. Dosłowny ciąg typulet test = "hello world"
ma&'static str
typ.test
jest odniesieniem do tego statycznie przydzielonego ciągu.&str
nie można na przykład modyfikowaćstr
ma zmienny plasterek&mut str
, na przykład:pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str)
Ale niewielka zmiana w UTF-8 może zmienić jego długość bajtu, a plasterek nie może ponownie przydzielić swojego odniesienia.
źródło
Krótko mówiąc,
String
typ danych jest przechowywany na stercie (podobnie jakVec
) i masz dostęp do tej lokalizacji.&str
jest rodzajem plastra. Oznacza to, że jest to tylko odniesienie do już istniejącegoString
gdzieś na stosie.&str
nie dokonuje żadnej alokacji w czasie wykonywania. Tak więc ze względu na pamięć możesz użyć&str
ponadString
. Pamiętaj jednak, że podczas używania&str
możesz mieć do czynienia z jawnym życiem.źródło
str
jestview
już obecneString
w kupie.Dla osób C # i Java:
String
===StringBuilder
&str
Ciąg Rust === (niezmienny)Lubię myśleć o
&str
widoku jako o łańcuchu, jak o internowanym łańcuchu w Javie / C #, w którym nie można go zmienić, wystarczy utworzyć nowy.źródło
Oto szybkie i łatwe wyjaśnienie.
String
- Rosnąca, dostępna struktura danych przydzielana do sterty. Można go przymusić do&str
.str
- jest (teraz, w miarę rozwoju Rust) zmiennym ciągiem o stałej długości, który żyje na stercie lub w pliku binarnym. Możesz wchodzić w interakcje tylko zstr
pożyczonym typem za pomocą widoku wycinka ciągu, takiego jak&str
.Uwagi dotyczące użytkowania:
Preferuj,
String
jeśli chcesz posiadać lub mutować ciąg - na przykład przekazując ciąg do innego wątku itp.Preferuj,
&str
jeśli chcesz mieć ciąg tylko do odczytu.źródło