Запутанное поведение при разыменовании изменяемой ссылки

#rust

#Ржавчина

Вопрос:

У меня есть функция, которая принимает изменяемую ссылку на строку и добавляет некоторый текст.

 fn append_str(s: amp;mut String) {
    s.push_str(" hi");
}
  

Предположим, у меня есть строка.

 let mut s: String = "hi".to_string();
  

Если я создаю изменяемую ссылку на s и передаю ее append_str , она компилируется без проблем.

 let mut ss = amp;mut s;

append_str(amp;mut ss);
  

Однако, если я явно определяю ss с amp;mut String помощью, он не компилируется.

 let ss: amp;mut String = amp;mut s;
append_str(amp;mut ss);
  

это показывает следующую ошибку компилятора.

    |
80 |     let ss: amp;mut String = amp;mut s;
   |         -- help: consider changing this to be mutable: `mut ss`
81 |     append_str(amp;mut ss);
   |                ^^^^^^^ cannot borrow as mutable
  

Забавно то, что если я разыменую ее, то это сработает.

 let ss: amp;mut String = amp;mut s;
append_str(amp;mut *ss); // OK
  

По какой причине мы должны явно разыменовывать в этом случае?

Еще один вопрос: почему мы должны указывать mut на ссылку, если мы хотим передать ее функции?

 let ss = amp;mut s;
append_str(amp;mut ss); // ERROR
  

Ответ №1:

ss это уже ссылка, поэтому amp;mut ss дает вам (изменяемую) ссылку на (изменяемую) ссылку; если у вас есть ss , вы должны вызвать append_str с ней напрямую: append_str(ss) .

Это происходит только тогда, когда вы неправильно принимаете изменяемую ссылку на ss , вам нужно объявить ее как mut ss . Обычный вариант использования для чего-то подобного — передать это функции, которая фактически принимает x: amp;mut amp;mut String и использует что-то вроде *x = amp;mut some_other_string , чтобы сделать ss ссылку на другую ссылку на строку. В вашем случае «исправленный» код с mut компилируется, потому что компилятор автоматически разыменовывает двойную ссылку для вас.