#string #rust #ownership
Вопрос:
Я изучаю Rust, и глава 8.2 книги по языку программирования Rust вызвала некоторые сомнения:
let mut s1 = String::from("foo"); let s2 = "bar"; s1.push_str(s2); println!("s2 is {}", s2);
Если
push_str
бы метод стал владельцемs2
, мы не смогли бы напечатать его значение в последней строке.
Я понимаю это и тот факт, что объединение добавляет только ссылку на строку и не получает ее права собственности. Это должно означать, что если s2
выходит за рамки или изменяется, объединенная строка должна быть освобождена или изменена, но этого не происходит:
let mut s1 = String::from("foo");
{
let mut s2 = String::from("bar");
s1.push_str(amp;s2[..]);
println!("s2 is {}", s2);
println!("s1 is {}", s1);
s2 = String::from("lol");
println!("s2 is {}", s2);
}
println!("Value after change is {}", s1);
Поскольку объединенная строка является только ссылкой на строку s2
и s1
не получает права собственности на строку, как только s2
она выходит за рамки области действия, кто является владельцем объединенной строки?
Комментарии:
1. Объединенная строка-это просто
s1
, которая объявляется изменяемой и действительно мутируетсяpush_str
методом.2. «объединенная строка является только ссылкой на строку s2» Что вы здесь имеете в виду ?
s1.push_str(amp;s2[..]);
копирует байтыamp;s2[..]
в буферs1
.3. Строки Rust хранятся в непрерывном массиве байтов, поэтому
push_str
у него нет другого выбора, кроме как копировать. Даже если бы он взял на себя ответственность за свой аргумент, ему все равно пришлось бы копировать, единственная разница заключалась бы в том, что память другой строки была бы освобождена одновременно.4. Я имею в виду, что когда вы используете
amp;
переменную, она просто заимствует выделенную память, не копирует ее и не присваивает ее себе, я не прав? Может быть, я просто запутался в этой главе, так как в ней не упоминается, что этоpush_str
копированиеamp;str
вString
значение5. @BogdanPop Вы правы, что простая передача ссылки не является копированием базовых данных. Но что функция, которую вы вызываете, будет делать с этой ссылкой, — это совершенно другой вопрос.
push_str()
добавит (скопирует) данные из ссылки на данную строку, потому что для этого она предназначена. Функция с именемcalc_sha1()
может просто изучить данные для вычисления контрольной суммы и никогда не копировать ее. Функция поиска строк может просматривать только часть данных и останавливаться после поиска строки, которую она ищет.
Ответ №1:
String
и str
хранятся в виде непрерывных массивов размером UTF-8 байт.
String "foo" amp;str "bar"
[ len: 3 | data:┐ ] [ len: 3 | data:┐ ]
│ │
v v
[ f | o | o ] [ more memory... ] [ b | a | r ]
Когда вы это сделаете s1.push_str(amp;s2[..])
, байты s2
будут скопированы в конец памяти, принадлежащей s1
(возможно, перераспределены, чтобы освободить больше места), оставив s2
все как есть.
┌────────────────────┐
v │
[ f | o | o | b | a | r ] [ b | a | r ]
Тот факт, что базовые байты должны быть смежными, означает, что невозможно выполнить операцию добавления без копирования с String
amp;str
типами / Rust. Для такой операции потребуется тип строки, реализованный, например, как связанный список фрагментов строк, а не один непрерывный массив.
Комментарии:
1. » связанный список фрагментов строк «… или a
Vec<amp;str>
.2. или веревку