В чем разница между Rust's `String` и `str`?
почему ржавчина есть String
и str
? В чем разница между String
и str
? Когда можно использовать String
вместо str
и наоборот? Один из них становится устаревшим?
6 ответов:
String
- это динамический тип строки кучи, напримерVec
: используйте его, когда вам нужно иметь или изменить строковые данные.
str
- это неизменяемая1 последовательность UTF-8 байт динамической длины где-то в памяти. Поскольку размер неизвестен,его можно обрабатывать только за указателем. Это значит, чтоstr
чаще всего2 появляется&str
: ссылка на некоторые данные UTF-8, обычно называемые " строковым срезом "или просто"срезом". A кусочек это просто представление некоторых данных, и эти данные могут быть где угодно, например
- в статическом хранилище: строковый литерал
"foo"
это&'static str
. Данные зашиты в исполняемый файл и загружаются в память при запуске программы.- внутри кучи выделяется
String
:String
разыменовывает к&str
посмотреть на 'ы.в стеке: например, следующее создает массив байтов, выделенный стеком, и затем получает просмотр этих данных, как
&str
:use std::str; let x: &[u8] = &[b'a', b'b', b'c']; let stack_str: &str = str::from_utf8(x).unwrap();
в общем, используйте
String
Если вам нужны собственные строковые данные (например, передача строк другим задачам или их построение во время выполнения), и используйте&str
если вам нужно только посмотреть на строку.это идентично отношению между вектором
Vec<T>
и кусок&[T]
, и похож на отношение между по-значениюT
и по ссылке&T
для общего типы.
1 A
str
фиксированная длина; вы не можете писать байты за пределами конца или оставлять конечные недопустимые байты. Поскольку UTF-8 является кодировкой переменной ширины, это эффективно заставляет всеstr
s, чтобы быть неизменными. В общем, мутация требует записи большего или меньшего количества байтов, чем было раньше (например, заменаa
(1 байт) сä
(2 + байт) потребуется сделать больше места вstr
).2 в момент он может только появляются как
&str
, а типы динамического размера может позволить такие вещи, какRc<str>
для последовательности ссылок подсчитывается UTF-8 байт. Это также не может,str
не совсем вписывается в схему DST отлично, так как нет версии фиксированного размера (пока).
у меня есть фон C++, и я нашел его очень полезным, чтобы думать о
String
и&str
В C++ Условия:
- П
String
какstd::string
; Она владеет памятью и выполняет грязную работу по управлению памятью.- П
&str
какchar*
(но немного более сложный); он указывает нам на начало куска таким же образом, вы можете получить указатель на содержимоеstd::string
.кто-нибудь из них собирается исчезнуть? Я так не думаю. Они служат двум целям:
String
сохраняет буфер и очень практичен в использовании.&str
легкий и должен использоваться, чтобы "смотреть" в строки. Вы можете искать, разбивать, анализировать и даже заменять куски без необходимости выделять новую память.
&str
может заглянуть внутрьString
как это может указывать на строковый литерал. Следующий код должен скопировать литеральную строку вString
управлял память:let a: String = "hello rust".into();
следующий код позволяет использовать сам литерал без копирования (только для чтения)
let a: &str = "hello rust";
они на самом деле совершенно разные. Во-первых,
str
- это не что иное, как вещь уровня типа; ее можно рассуждать только на уровне типа, потому что это так называемый тип динамического размера (DST). Размерstr
занимает не может быть известно во время компиляции и зависит от информации во время выполнения - он не может быть сохранен в переменной, потому что компилятор должен знать во время компиляции, каков размер каждой переменной. Аstr
концептуально просто строкаu8
байт с гарантируйте, что он формирует действительный UTF-8. Насколько велика эта строка? Никто не знает, пока время выполнения, следовательно, он не может быть сохранен в переменной.самое интересное, что a
&str
или любой другой указатель наstr
какBox<str>
тут существуют во время выполнения. Это так называемый" жирный указатель"; это указатель с дополнительной информацией (в данном случае размер вещи, на которую он указывает), поэтому он в два раза больше. В самом деле,&str
довольно близко кString
(но не&String
). А&str
- это два слова; один указатель на первый байт astr
и еще одно число, которое показывает, сколько байт в элементеstr
есть.вопреки тому, что сказано, a
str
не должен быть неизменяемым. Если вы можете получить&mut str
как эксклюзивный указатель наstr
, вы можете мутировать его, и все безопасные функции, которые мутируют его, гарантируют, что ограничение UTF-8 поддерживается, потому что если это нарушается, то у нас есть неопределенное поведение в качестве библиотеки предполагается, что это ограничение истинно и не проверяет его.что это
String
? Это три слова; два такие же, как для&str
но он добавляет третье слово, которое является емкостьюstr
буфер в куче, всегда в куче (astr
Не обязательно в куче) он управляет до его заполнения и должен перераспределить. элементString
в принципе принадлежит astr
как говорится; он управляет им и может изменять его размер и перераспределять его, когда он считает нужным. Так чтоString
как сказано ближе к a&str
чемstr
.другое дело
Box<str>
; это также принадлежитstr
и его представление во время выполнения совпадает с&str
, но он также принадлежитstr
в отличие от&str
но он не может изменить его размер, потому что он не знает его емкость так в основном aBox<str>
можно рассматривать как фиксированную длинуString
это не может быть изменено (вы всегда можете преобразовать его вString
если вы хотите изменить его размер).A очень похожие отношения существуют между
[T]
иVec<T>
за исключением того, что нет ограничения UTF-8, и он может содержать любой тип, размер которого не является динамическим.использование
str
на уровне типа, в основном, для создания родовых абстракций с&str
; Она существует на уровне типа, чтобы иметь возможность удобно писать черты. В теорииstr
как тип вещь не должна существовать и только&str
но это означало бы, что нужно будет написать много дополнительного кода, который теперь может быть родовой.
&str
очень полезно иметь возможность иметь несколько разных подстрокString
без необходимости копировать; как сказалString
принадлежит thestr
в куче он управляет, и если бы вы могли только создать подстроку aString
новаяString
он должен быть скопирован, потому что все в Rust может иметь только одного владельца, чтобы иметь дело с безопасностью памяти. Так, например, вы можете нарезать строку:let string: String = "a string".to_string(); let substring1: &str = &string[1..3]; let substring2: &str = &string[2..4];
у нас есть два разных подстрока
str
s той же строки.string
это тот, который владеет фактическим полнымstr
буфер в куче и&str
подстроки-это просто жирные указатели на этот буфер в куче.
проще говоря,
String
тип данных хранится в куче так же, какVec
и у вас есть доступ к указатель на это место.
&str
тип среза. Это означает, что это просто ссылка на уже существующийString
где-то в куче.
&str
не делает никакого выделения во время выполнения. Итак, по соображениям памяти вы можете использовать&str
overString
. Но, имейте в виду, что при использовании&str
возможно, вам придется иметь дело с явными жизнями.