Rust: str vs String
Будучи новичком в Rust, я запутывался в различных способах представления строк.
В книге о языке Rust есть глава «References and Borrowing», в которой
используется три различных типа строковых переменных в примерах: String
, &String
и &str
.
Начнём с разницы между str
и String
: String
— это расширяемая, выделяемая на куче структура данных, тогда как str
— это неизменяемая строка фиксированной длины, где-то в памяти.
String
Если вы программируете на Java, String
в Rust семантически эквивалентен StringBuffer
(вероятно это являлось причиной моего замешательства, поскольку я привык приравнивать String
с неизменяемостью). Таким образом, String
имеет длину и вместимость, тогда как str
имеет только один метод len()
. В качестве примера:
1 2 3 4 5 6 7 8 9 10 11 | let mut s = String::from("Привет, Rust!"); println!("{}", s.capacity()); // напечатает 19 s.push_str("Вот и я!"); println!("{}", s.len()); // напечатает 32 let s = "Привет, Rust!"; // ошибка компиляции: для типа `str` не найден // метод с именем `capacity`. println!("{}", s.capacity()); println!("{}", s.len()); // напечатает 19 |
& str
Вы можете взаимодействовать с str
в качестве заимствованного типа &str
. Это называется строковый срез (слайс), неизменяемое представление строки. Как мы увидим, этот способ является предпочтительным для передачи строк.
& String
Это ссылка на String
, которая также является заимствованным типом. Это не более чем указатель, который вы можете передать, не передавая владение. Получается, что &String
можно привести к &str
:
1 2 3 4 5 6 7 8 | fn main() { let s = String::from("Привет, Rust!"); foo(&s); } fn foo(s: &str) { println!("{}", s); } |
В приведённом выше примере, foo()
может принимать любой строковый срез (слайс) или заимствованный String
, что очень удобно. Таким образом, вам почти никогда не надо иметь дело со &String
. Единственный случай применения, который приходит мне в голову — если вы хотите передать изменяемую ссылку в функцию, которая должна изменить строку:
1 2 3 4 5 6 7 8 9 | fn main() { let mut s = String::from("Привет, Rust!"); foo(&mut s); } fn foo(s: &mut String) { s.push_str("добавим foo.."); println!("{}", s); } |
Подводя итог
Предпочитайте &str
, чтобы передать параметр в функцию или если вам нужно неизменяемое представление строки. А String
, когда вы хотите владеть и изменять строку.
- Данные
str
могут находиться в куче, стеке или в исполняемом файле. Этот отличный ответ на stackoverflow объясняет каждый случай.