2016-06-13 13 views
2

Betrachten Sie die folgenden zwei Strukturen:Ist es möglich, einen Teil einer Struktur als Referenz zurückzugeben?

pub struct BitVector<S: BitStorage> { 
    data: Vec<S>, 
    capacity: usize, 
    storage_size: usize 
} 

pub struct BitSlice<'a, S: BitStorage> { 
    data: &'a [S], 
    storage_size: usize 
} 

Wo BitStorage ist praktisch eine Art, die für alle unsignierten ganzen Zahlen beschränkt ist (U8, U16, U32, U64, USIZE).

Wie implementiert man die Deref Eigenschaft? (BitVector<S> derefs zu BitSlice<S> ähnlich, wie Vec<S> derefs zu &[S])

Ich habe versucht, die folgenden (Beachten Sie, dass es nicht aufgrund von Problemen mit Lebensdauern nicht kompiliert, aber noch wichtiger ist, weil ich versuche, einen Wert auf dem Stack zurückzukehren, wie eine Referenz):

impl<'b, S: BitStorage> Deref for BitVector<S> { 
    type Target = BitSlice<'b, S>; 

    fn deref<'a>(&'a self) -> &'a BitSlice<'b, S> { 
     let slice = BitSlice { 
      data: self.data, 
      storage_size: self.storage_size, 
     }; 
     &slice 
    } 
} 

ich weiß, dass es möglich ist, ein Feld einer Struktur unter Bezugnahme auf zurückkehren, so zum Beispiel ich &Vec<S> oder &usize im Deref Zuge zurückkehren könnte, aber ist es möglich, ein BitSlice zurück Beachten Sie, dass ich im Wesentlichen alle Daten in derhaben 210 schon als Vec<S> kann in &[S] umgewandelt werden und ist schon da?

Ich denke, das ist möglich, wenn ich eine Struktur mit beiden Werten erstellen könnte und den Compiler irgendwie anweisen, die Tatsache zu ignorieren, dass es eine Struktur ist, die auf dem Stapel erstellt wird und stattdessen nur die vorhandenen Werte verwendet, aber ich habe habe keine Ahnung wie.

Antwort

2

Deref wird benötigt, um eine Referenz zurückzugeben. Eine Referenz immer verweist auf einen vorhandenen Speicher, und jede lokale Variable wird nicht lange genug existieren. Während es theoretisch einige Tricks gibt, die Sie spielen könnten, um ein neues Objekt in deref zu erstellen und einen Verweis darauf zurückzugeben, führt alles, was mir bekannt ist, zu einem Speicherleck. Lassen Sie uns diese technischen Details ignorieren und einfach sagen, dass es unmöglich ist.

Was nun? Sie müssen Ihre API ändern. Vec kann Deref implementieren, weil es zu [T] dereferenziert, nicht zu &[T] oder etwas ähnliches. Sie können mit der gleichen Strategie Erfolg haben: Machen Sie BitSlice<S> einen nicht standardisierten Typ, der nur eine Scheibe [S] enthält, so dass der Rückgabetyp &'a BitSlice<S> ist. Dies setzt voraus, dass das Mitglied nicht benötigt wird. Aber es scheint, dass sich dies auf die Anzahl der Bits bezieht, die logisch gültig sind (d. H. Auf sie kann zugegriffen werden, ohne den Bitvektor zu erweitern). — Wenn dies der Fall ist, scheint dies unvermeidbar zu sein. . Die andere Alternative ist natürlich, Deref nicht zu implementieren. Ungünstig, aber wenn Ihr Schnittdatentyp zu weit von einer tatsächlichen Scheibe entfernt ist, ist dies möglicherweise die einzige Option.

RFC PR #1524, die benutzerdefinierten dynamisch große Typen vorgeschlagen, dann könnten Sie eine Art BitSlice<S> haben, die wie eine Scheibe ist, aber zusätzliche Inhalte wie storage_size haben. Dies existiert jedoch noch nicht und es ist bei weitem nicht sicher, ob es jemals möglich sein wird.

Die capacity Mitglied auf BitVector scheint jedoch sinnlos. Ist das nicht nur sizeof S * 8?

+0

Sie sind richtig in Ihrer Annahme, dass 'storage_size' nicht benötigt wird, es ist nur' std :: mem :: size_of :: () * 8', aber ich habe Angst, dass 'Kapazität' benötigt wird, wie Sie zuordnen könnten ein Bitvektor, der kein Mehrfaches des Hintergrundspeichers ist, d.h. Sicherungsspeicher ist u32 und Sie möchten 50 Bits zuweisen, obwohl es sinnvoll sein könnte, die Zuweisung in Vielfachen des Sicherungsspeichers zu erzwingen, wenn dies das Funktionieren des Derefing ermöglicht – skiwi

Verwandte Themen