Как заимствовать как изменяемый против неизменного в Rust? - PullRequest
3 голосов
/ 20 февраля 2020

Я прочитал эти документы: https://doc.rust-lang.org/rust-by-example/scope/borrow/mut.html

Я также читал этот вопрос: ( Невозможно заимствовать неизменное заимствованное содержимое как изменяемое )


Документы помогли мне понять, как объявить заимствования как изменяемые (я думаю):

let mut (part1, part2) = someTuple;

Но я не смог найти четких инструкций о том, что заимствовать как неизменным выглядит Это мое предположение:

let (part1, part2) = someTuple;

Я знаю, что это супер базовый c вопрос, но поиск в Google привел меня к глубокому концу объяснений, и я все еще пытаюсь получить мои ориентиры в самом простом контексте.

Как я могу заимствовать изменчивое и неизменное в Rust?

Ответы [ 2 ]

2 голосов
/ 20 февраля 2020

Ответы Ejdrien демонстрируют разницу между изменчивыми и неизменяемыми заимствованиями, однако не учитывают подзаголовок в вашем вопросе, который заключается в том, что вы выполняете заимствования как часть сопоставления с шаблоном .

Когда вы пишете

let (mut part1, mut part2) = someTuple;

, вы связываете содержимое someTuple с изменяемыми переменными part1 и part2 с помощью , перемещая их. Если содержимое someTuple не было в состоянии Copy, переменные part1 и part2 становятся исключительными владельцами своих соответствующих значений. Если вы попытаетесь получить доступ к someTuple позже, написав, например,

println!("{}", someTuple.0);

, вы получите сообщение об ошибке компиляции из средства проверки заимствования, которое напоминает

error[E0382]: borrow of moved value: `someTuple.0`
 --> main.rs:6:20
  |
4 |     let (mut part1, mut part2) = someTuple;
  |          --------- value moved here
5 | 
6 |     println!("{}", someTuple.0);
  |                    ^^^^^^^^^^^ value borrowed here after move

В этом конкретном контексте Есть два способа сообщить компилятору, что мы хотим заимствовать только содержимое someTuple. Первым является метод, описанный Эйдриеном, который явно заимствует кортеж и выполняет сопоставление с шаблоном с последующей результирующей ссылкой:

// Produce two mutable references
let (part1, part2) = &mut someTuple;

// Produce two immutable references
let (part1, part2) = &someTuple;

Проблема этого подхода заключается в том, что мы вынуждены заимствовать все таким же образом. Что если нам нужна только изменчивая ссылка на someTuple.0 и мы хотим получить someTuple.1 как копию или неизменную ссылку? Для приведенного здесь примера кортежа это может показаться не слишком критичным, но для более сложных случаев сопоставления с образцом гораздо важнее иметь этот тип элемента управления.

Это дает нам два вторых решения: привязка ссылок. Вместо вышесказанного мы можем написать

// Produce two mutable references
let (ref mut part1, ref mut part2) = someTuple;

// Produce two immutable references
let (ref part1, ref part2) = someTuple;

Здесь мы явно указываем, как мы хотим связать каждую переменную в сопоставлении с образцом. Ключевым моментом здесь является то, что мы можем смешивать изменяемые и неизменяемые заимствования, поэтому следующее также полностью допустимо:

// Produce immutable reference and one mutable reference
let (ref part1, ref mut part2) = someTuple;

println!("{}", &someTuple.0); // Make a second immutable reference someTuple.0
*part2 = ... // Mutate someTuple.1
println!("{}", part1); // Continue using the immutable reference

Если мы поменяем вышеуказанное с явным изменяемым заимствованием в правой части, мы ' Я снова получу ошибки от заемщика из-за одновременных изменяемых и неизменяемых ссылок:

let (part1, part2) = &mut someTuple;

println!("{}", &someTuple.0);
*part2 = ... // Mutate someTuple.1
println!("{}", part1);

производит

error[E0502]: cannot borrow `someTuple.0` as immutable because it is also borrowed as mutable
 --> main.rs:6:20
  |
4 |     let (part1,part2) =&mut someTuple;
  |                        -------------- mutable borrow occurs here
5 | 
6 |     println!("{}", &someTuple.0);
  |                    ^^^^^^^^^^^^ immutable borrow occurs here
...
9 |     println!("{}", part1);
  |                    ----- mutable borrow later used here

error: aborting due to previous error

2 голосов
/ 20 февраля 2020
let x = 0;
let immutable_borrow = &x; //borrow as immutable

//to borrow as mutable the variable needs to be declared as mutable
let mut y = 1;
let mutable_borrow = &mut y; //borrow as mutable

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

let mut x = 0;
let immutable_borrow = &x;
let mutable_borrow = &mut x;

Почему?

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


Примечание 2 : вы можете бесконечно одалживать переменную бесконечное время, но вы можете односторонне одолжить переменную только один раз.

//You can do this
let x = 0;
let x1 = &x;
let x2 = &x;
//...

//But you can't do this
let mut y = 0;
let y1 = &mut y;
let y2 = &mut y; //won't compile

Почему?

Как указано выше. Одна изменяемая ссылка может изменить данные, на которые ссылаются все другие изменяемые ссылки, без их ведома. Это может вызвать много проблем. Но иметь несколько неизменных ссылок - это нормально, потому что данные не могут быть неожиданно изменены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...