В чем разница между 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 является кодировкой переменной ширины, это эффективно заставляет всеstrs, чтобы быть неизменными. В общем, мутация требует записи большего или меньшего количества байтов, чем было раньше (например, замена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];у нас есть два разных подстрока
strs той же строки.stringэто тот, который владеет фактическим полнымstrбуфер в куче и&strподстроки-это просто жирные указатели на этот буфер в куче.
проще говоря,
Stringтип данных хранится в куче так же, какVecи у вас есть доступ к указатель на это место.
&strтип среза. Это означает, что это просто ссылка на уже существующийStringгде-то в куче.
&strне делает никакого выделения во время выполнения. Итак, по соображениям памяти вы можете использовать&stroverString. Но, имейте в виду, что при использовании&strвозможно, вам придется иметь дело с явными жизнями.