Кто является владельцем связанной строки, как только ее владелец выходит за пределы области видимости?

#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. или веревку