2015-10-11 19 views
7

Sto imparando Rust e ho avuto qualche comportamento confuso. Il seguente codice compila bene e funziona come previsto (modificare: aggiunto codice diverso da funzione di test, in precedenza omesso):Tipo di inferenza e prestito contro trasferimento di proprietà

struct Container<'a> { 
    contents : &'a mut i32, 
} 

fn main() { 
    let mut one = Container { contents: &mut 5 }; 
    test(&mut one); 
    println!("Contents: {}",one.contents); 
} 

fn test<'a>(mut x : &'a mut Container) { 
    *x.contents += 1; 
    let y = x; 
    *y.contents += 1; 
    x = y; 
    println!("{:?}",*x.contents) 
} 

Ora nella dichiarazione

let y = x; 

il tipo è dedotto. Perché x è di tipo &'a mut Container, ho pensato che questo sarebbe equivalente:

let y: &'a mut Container = x; 

Ma quando lo faccio, il compilatore contesta:

test_3.rs:25:5: 25:10 error: cannot assign to `x` because it is borrowed 
test_3.rs:25  x = y; 
       ^~~~~ 
test_3.rs:23:33: 23:34 note: borrow of `x` occurs here 
test_3.rs:23  let y: &'a mut Container = x; 

Come è x non preso in prestito da quel punto del esempio di lavoro corretto? Ho testato omettendo la linea x = y; dalla versione funziona correttamente e il compilatore detto:

test_3.rs:24:13: 24:14 note: `x` moved here because it has type `&mut Container<'_>`, which is moved by default 

Così sto ottenendo una mossa quando non definisce esplicitamente il tipo, ma un prestito altrimenti. Che cosa sta succedendo, come faccio a ottenere lo stesso comportamento di prima mentre esprimo esplicitamente il tipo, e cosa sta causando il comportamento di movimento in un caso, ma prestito nell'altro?

cura con programma completo

+2

Forse un [esempio come questo] (http://is.gd/Ht32Jl)? – Shepmaster

+0

Ciao, mi dispiace; ecco un [codice completo] (http://is.gd/9oz2kT). Il tuo esempio cattura esattamente il problema. –

+1

Correlati: http://stackoverflow.com/q/32154387/1763356 – Veedrac

risposta

6

Quando si esegue

let y = x; 

una mossa accade. x viene svuotato, per così dire, e la proprietà viene trasferita a .

Quando si esegue una delle

let y: &mut _ = x; 
let y: &'a mut _ = x; 

x è reborrowed per aiutare corrispondere i tempi di vita. Questo si traduce all'incirca

let y: &mut _ = &mut *x; 
let y: &'a mut _ = &mut *x; 

Questo lascia x non vuoto, in possesso di un prestito mutevole alias. Assegnare così deve aspettare che venga distrutto. In alternativa, è possibile pre-spostarlo

let tmp = x; 
let y: &'a mut _ = tmp; 

devo ammettere che è un comportamento non ovvia, ed è un peccato che non si può prendere in prestito il contenuto di un valore senza prendere in prestito l'intero valore.

+1

* in possesso di un mutuo mutilato con alias * - Avevo l'impressione che ciò sia chiaramente una cosa che Rust proibisce sicuro? – Shepmaster

+3

Rust non vieta i mutanti mutuatari aliasati: vieta di usarne più di uno alla volta o di sovrapporli in modi non lessicali. Quando scrivi '& mut x',' x' è ancora una posizione di stack valida - non è legale leggere o scrivere ad essa. – Veedrac

+0

Interessante. Mi sono sempre chiesto quali siano le regole esatte che il compilatore usa per determinare il movimento-contro-reborrow.Fino ad ora, ho ipotizzato che il rimpatrio avvenga solo nelle chiamate di funzione dove la funzione prende un '& mut'. Ma apparentemente, essere più espliciti * all'interno di * una funzione si qualifica anche per un re-trasferimento. – sellibitze