2015-01-12 8 views
5

Ho problemi a comprendere il motivo ref in Rust. Mi riferisco a https://rustbyexample.com/scope/borrow/ref.htmlRuggine con l'esempio: il modello di rif.

Ecco il codice che non capisco:

let point = Point { x: 0, y: 0 }; 

let _copy_of_x = { 
    // `ref_to_x` is a reference to the `x` field of `point` 
    let Point { x: ref ref_to_x, y: _ } = point; 

    // Return a copy of the `x` field of `point` 
    *ref_to_x 
}; 

ottengo che l'ultima let espressione è una sorta di pattern matching (?). Quindi è a mia conoscenza che ref ref_to_x deve essere uguale a 0, il valore x dell'originale point.

Ma non capisco cosa faccia effettivamente lo ref. Quando aggiungo un po 'di codice come questo:

println!("x: {}", point.x); 
println!("ref_to_x: {}", ref_to_x); 
println!("*ref_to_x: {}", *ref_to_x); 

ottengo sempre 0, quindi non sembra essere una differenza. In qualche modo mi aspetterei un indirizzo di memoria per ref_to_x mentre *ref_to_x potrebbe essere nuovamente il valore di riferimento.

Posso sostituire sia ref ref_to_x e *ref_to_x con myx e il codice funziona ancora. Qual è la differenza? Cosa fa esattamente ref?

modifica: dopo aver letto dbaupps risposta e facendo qualche aggiunta con ref_to_x e *ref_to_x le cose sono diventate un po 'più chiare; non è possibile aggiungere un numero intero a ref_to_x perché è un riferimento. Immagino di essere confuso perché non c'è alcuna indicazione di un riferimento quando ne stampi uno.

risposta

10

ref crea un puntatore nel pezzo di memoria che viene abbinato su, in questo caso, ref_to_x punta direttamente alla memoria che memorizza point.x, è lo stesso che scrivere let ref_to_x = &point.x in questo caso.

Il modello è estremamente importante poiché consente di raggiungere in profondità strutture di dati complesse senza disturbare la gerarchia della proprietà. Ad esempio, se uno ha val: &Option<String>, scrivendo

match *val { 
    Some(s) => println!("the string is {}", s), 
    None => println!("no string" 
} 

non è legale, dà un errore del tipo:

<anon>:3:11: 3:15 error: cannot move out of borrowed content 
<anon>:3  match *val { 
        ^~~~ 
<anon>:4:14: 4:15 note: attempting to move value to here 
<anon>:4   Some(s) => {} 
        ^
<anon>:4:14: 4:15 help: to prevent the move, use `ref s` or `ref mut s` to capture value by reference 
<anon>:4   Some(s) => {} 
        ^

Non è legale per assumere la proprietà (spostamento) di un valore preso in prestito, perché ciò potrebbe danneggiare la cosa da cui il valore è stato preso in prestito (violando i suoi invarianti, causando la scomparsa inaspettata dei dati, ecc.).

Quindi, si può invece utilizzare un riferimento per puntare semplicemente in memoria con un riferimento in prestito &.


C'è una leggera sottigliezza qui perché (a) point non è preso in prestito, quindi è OK per uscire da point (che consuma la proprietà del point troppo, il che significa che non può essere utilizzato in seguito a meno che reinizializzato) e (b) il tipo è Copy, quindi non si sposta la proprietà se utilizzato dal valore. Questo è il motivo per cui l'uso di myx funziona bene. Se il tipo di(che non è Copy) e point è stato preso in prestito, il tiposarà preso in prestito, quindi sarà necessario il numero ref.

11

Un riferimento creato con ref è esattamente lo stesso riferimento utilizzato con &.

La differenza è dove sono consentiti nella sintassi. ref sul lato sinistro di un compito è come aggiungere & sul lato destro.

Queste espressioni sono equivalenti:

let ref x1 = y; 
let x2 = &y; 

esiste Questa ridondanza perché nel pattern matching & viene utilizzato per richiedere che un riferimento già esistente, anziché fare uno nuovo:

let foo = 1; 
match foo { 
    ref x => { 
     /* x == &1 */ 
     match x { 
      &y => /* y == 1 */ 
     } 
    }, 
} 

(discussion)