2016-06-24 2 views
1

У меня возникла проблема с некоторым кодом Rust, где мне разрешено брать что-то как изменчивое более одного раза на определенные условия (первая запутанная часть), но не другие.Rust Borrow checker только жалуется на заимствование как изменяемое несколько раз, когда функция, возвращающая ссылку с тем же назначением жизни, назначается

Я написал следующий пример для иллюстрации: (Playground)

struct NoLifetime {} 
struct WithLifetime <'a> { 
    pub field: &'a i32 
} 

fn main() { 
    let mut some_val = NoLifetime {}; 
    borrow_mut_function(&mut some_val); 
    borrow_mut_function(&mut some_val); // Borrowing as mutable for the second time. 

    let num = 5; 
    let mut life_val = WithLifetime { field: &num }; 
    borrow_lifetime(&mut life_val); 
    borrow_lifetime(&mut life_val); // Borrowing as mutable for the second time. 

    let num_again = borrow_lifetime(&mut life_val); // Borrow, assign lifetime result 
    borrow_lifetime(&mut life_val); // Compiler: cannot borrow `life_val` as mutable more than once 
} 

fn borrow_mut_function(val_in: &mut NoLifetime) -> String { 
    "abc".to_string() 
} 
fn borrow_lifetime<'a>(val_in: &'a mut WithLifetime) -> &'a i32 { 
    val_in.field 
} 

Если вы видите, я могу взять как some_val и life_val изменяемым более чем один раз. Однако после присвоения возвращаемого значения borrow_lifetime я больше не могу брать взаймы.

Моих вопросов следующие:

  1. От «правил» о привлечении в Rust Book, я должен иметь «ровно один изменяемую ссылку» в области применения на ту же величину. Однако в приведенном выше коде я заимствую как изменяемый каждый раз, когда я вызываю функцию borrow_.
  2. Почему один и тот же тип заимствований не допускается, когда у меня есть функция, которая возвращает что-то с тем же временем жизни, что и параметр, и я назначаю этот параметр.

Любая помощь будет оценена по достоинству. Я представляю, что происходит здесь, что я не понимаю, что означает «заимствование как изменчивое», и когда нужно определить, что что-то заимствовано как изменчивое.

ответ

6

Крис уже дал суть, но я думаю, что это стоит объяснить далее.

Есть способы передачи собственности в Русте:

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

Ржавчина, как и многие другие языки, моделирует время прохождения, используя стек лексические области. В результате на данный момент, заимствование начинается там, где оно создано и распространяется до конца его объема.


Таким образом, вопросы, когда заимствуют заканчивается сродни спрашивая, что сфера является заимствуют создан в

Давайте рассмотрим ваш пример с пронумерованными строками:.

fn main() { 
1.  let mut some_val = NoLifetime {}; 
2.  borrow_mut_function(&mut some_val); 
3.  borrow_mut_function(&mut some_val); 

4.  let num = 5; 
5.  let mut life_val = WithLifetime { field: &num }; 
6.  borrow_lifetime(&mut life_val); 
7.  borrow_lifetime(&mut life_val); 

8. let num_again = borrow_lifetime(&mut life_val); 
9. borrow_lifetime(&mut life_val); 
    } 

Когда функция вызывается, аргумент занят:

  • как минимум на время вызова функции
  • до момента результат упал, если в результате акции на всю жизнь с аргументом

Итак, давайте посмотрим на это:

  • на линии (2) и (3) вы вызываете borrow_mut_function, который возвращает String: результат не имеет никакого ресурса с аргументом, поэтому аргумент используется только для жизни вызова функции.

  • на линии (6) и (7) Вы называете borrow_lifetime, которая возвращает &'a i32: результат акций жизни с аргументом, так что аргумент заимствован до конца рамки результата ... который сразу же, поскольку результат не используется.

  • на линии (8) вы звоните borrow_lifetime, который возвращает &'a i32 и вы назначить результат в num_again: результат акции пожизненный с аргументом, так что аргумент заимствован до конца сферы num_again.

  • on line (9) Вы звоните borrow_lifetime, однако его аргумент по-прежнему заимствует num_again, поэтому звонок является незаконным.

Вот и все, как работает Руста сегодня.


В будущем, есть призыв к без лексических заимствует. То есть, компилятор поймет, что:

  • num_again никогда не используется
  • num_again не имеет конкретного деструктор (без Drop реализации)

и, следовательно, может решить, что его заимствуют заканчивается раньше, чем конец лексического охвата.

Это часто запрашиваемая функция и ожидает внутреннего рефакторинга компилятора (введение MIR), который близится к завершению.

5

Речь идет о сфере охвата заимствования, и сохраняете ли вы свой долг. В большинстве вышеперечисленных вызовов some_val заимствован во время вызова функции, но возвращается после возвращения функции.

В случае исключения:

let num_again = borrow_lifetime(&mut life_val); //Borrow, assign lifetime result 

Вы заимствование life_val во время вызова borrow_lifetime, но так как возвращаемое значение имеет тот же срок службы в качестве параметра ('a), сфера Заимствование является расширена, чтобы включить время жизни num_again, т.е. до конца функции. Было бы небезопасно заимствовать life_val, так как num_again все еще является ссылкой на него.