2015-01-12 10 views
5

Ich habe Probleme mit dem Verständnis der ref Muster in Rust. Ich beziehe mich auf https://rustbyexample.com/scope/borrow/ref.htmlRust mit gutem Beispiel: Die ref Muster

Hier ist der Code, den ich nicht verstehe:

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 
}; 

ich, dass der letzte let Ausdruck eine Art Mustervergleich ist (?). So ist es mein Verständnis ref ref_to_x sollte 0, der x Wert der ursprünglichen point gleich sein.

Aber ich verstehe nicht, was die ref tatsächlich der Fall ist. Wenn ich einige Code wie folgt hinzu:

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

Ich bekomme immer 0, so scheint es kein Unterschied zu sein. Irgendwie würde ich eine Speicheradresse erwartet für ref_to_x während *ref_to_x könnte wieder den dereferenzierten Wert sein.

Ich kann sowohl als auch *ref_to_x durch myx ersetzen und der Code funktioniert immer noch. Was ist der Unterschied? Was macht ref genau?

edit: nach dem Lesen dbaupps beantworten und einige Ergänzungen mit ref_to_x und *ref_to_x Dinge tun, wurde ein bisschen klarer; Sie können ref_to_x keine ganze Zahl hinzufügen, weil es eine Referenz ist. Ich glaube, ich war verwirrt, weil es keinen Hinweis auf eine Referenz gibt, wenn Sie eine drucken.

Antwort

10

ref einen Zeiger in das Stück von Speicher erzeugt, der auf, in diesem Fall angepasst wird, wird ref_to_x zeigen direkt mit dem Speicher, die point.x speichert, ist es die gleiche wie let ref_to_x = &point.x in diesem Fall zu schreiben.

Das Muster ist äußerst wichtig, da es ein zu erreichen tief in komplizierten Datenstrukturen, ohne die Eigentumshierarchie ermöglicht. wenn man zum Beispiel, hat val: &Option<String>, Schreiben

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

nicht legal ist, gibt es einen Fehler wie:

<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) => {} 
        ^

Es ist nicht legal Besitz nehmen (move) aus einem geliehenen Wert, weil das würde möglicherweise das Ding beschädigen, von dem der Wert entlehnt wurde (seine Invarianten verletzend, Daten unerwartet verschwinden lassen, usw.).

So kann man stattdessen einen Verweis auf nur Punkt in dem Speicher mit einer Kreditaufnahme & Referenz verwenden.


Es gibt eine leichte Subtilität hier, weil (a) point nicht ausgeliehen wird, so dass es in Ordnung ist aus point zu bewegen (was auch das Eigentum an point verbraucht, es bedeutet, kann später nicht mehr verwendet werden, es sei denn, neu initialisiert) und (b) der Typ int ist Copy, also wird Eigentum nicht verschoben, wenn es nach Wert verwendet wird. Deshalb funktioniert die Verwendung von myx stattdessen gut. Wenn der Typ x beispielsweise String war (was nicht Copy ist) und point wurde ausgeliehen, dann wird ref erforderlich sein.

11

Eine mit ref erstellte Referenz entspricht genau der Referenz, die mit & erstellt wurde.

Der Unterschied ist, wo sie in der Syntax erlaubt sind. ref auf der linken Seite einer Zuweisung ist wie & auf der rechten Seite hinzufügen.

Diese Ausdrücke sind äquivalent:

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

Diese Redundanz besteht, weil in Pattern-Matching & verwendet wird zu verlangen, dass ein Verweis bereits vorhanden ist, anstatt ein neues zu machen:

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

(discussion)