2015-07-25 1 views
9

Ich lese die Dokumentation für Deref Merkmal des Rust:Warum ist der Rückgabetyp von Deref :: deref selbst eine Referenz?

pub trait Deref { 
    type Target: ?Sized; 
    fn deref(&self) -> &Self::Target; 
} 

Die Art Signatur für die deref Funktion erscheint unlogisch zu mir; Warum ist der Rückgabetyp eine Referenz? Wenn Referenzen dieses Merkmal so implementieren, dass es dereferenziert werden kann, welchen Effekt hätte das überhaupt?

Die einzige Erklärung, die ich finden kann, ist, dass Referenzen Deref nicht implementieren, aber als "primitiv dereferenziert" gelten. Wie aber würde eine polymorphe Funktion, die für irgendein dereferenzierbarer Typ funktionieren würde, einschließlich sowohl Deref<T> als auch &T, geschrieben werden?

+2

Das könnte Sie interessieren https://www.reddit.com/r/rust/comments/2umad5/the_output_of_the_index_trait_should_be_a_value/ –

+0

@JonasTepe Also, wenn ich das richtig zu verstehen, ist der Grund dafür, dass wir keine Funktionen angeben, die lvalues ​​zurückkehren , also machen wir es "manuell", indem wir einen Verweis auf einen L-Wert, den wir bereits haben, zurückgeben. – corazza

+0

Sie möchten den "richtigen" L-Wert zurückgeben. Bezeichnet den Wert, der Eigenname ist (der Wert, der von Deref implementiert wird). Du würdest keinen kurzlebigen Wert zurückgeben wollen.Dann könntest du genauso gut einen rvalue zurückgeben. Und der einzige Weg, dies zu tun, ist eine Referenz in sich selbst zu bringen. –

Antwort

9

dass Referenzen nicht implementieren Deref

Sie all the types that implement Deref sehen können, und &T ist in dieser Liste:

impl<'a, T> Deref for &'a T where T: ?Sized 

Die nicht-offensichtliche Sache ist, dass es syntaktische Zucker Wesen angewendet, wenn Sie den Operator * mit etwas verwenden, das Deref implementiert. Sehen Sie sich diese kleine Beispiel aus:

use std::ops::Deref; 

fn main() { 
    let s: String = "hello".into(); 
    let _:() = Deref::deref(&s); 
    let _:() = *s; 
} 
error[E0308]: mismatched types 
--> src/main.rs:5:17 
    | 
5 |  let _:() = Deref::deref(&s); 
    |     ^^^^^^^^^^^^^^^^ expected(), found &str 
    | 
    = note: expected type `()` 
      found type `&str` 

error[E0308]: mismatched types 
--> src/main.rs:6:17 
    | 
6 |  let _:() = *s; 
    |     ^^ expected(), found str 
    | 
    = note: expected type `()` 
      found type `str` 

Die expliziten Aufruf deref gibt ein &str, sondern der Betreiber * eine str zurückgibt. Es ist eher so, als würden Sie *Deref::deref(&s) aufrufen und die implizierte unendliche Rekursion ignorieren.

Xirdus is correct in saying

Wenn deref Wert zurückgegeben, wäre es entweder nutzlos sein, weil es immer heraus bewegen würde, oder Semantik, die drastisch von jeder anderen Funktion unterscheidet

Obwohl „nutzlos“ ist ein bisschen stark; Es wäre immer noch nützlich für Typen, die Copy implementieren.

3

Der Compiler weiß nur, wie man dereferenzieren & -pointers - aber er weiß auch, dass Typen, die Deref Merkmal haben eine deref() Methode implementieren, die einen entsprechenden Verweis auf etwas verwendet werden kann innerhalb Objekt abgerufen werden. Wenn Sie ein Objekt dereferenzieren, erhalten Sie zuerst die Referenz und erst dann die Dereferenzierung.

Wenn deref() einen Wert zurückgegeben hat, wäre es entweder nutzlos, weil es immer ausgezogen wäre, oder eine Semantik, die sich drastisch von jeder anderen Funktion unterscheidet, die nicht nett ist.