2015-07-28 5 views
13

Ich möchte ein Rc<str> erstellen, weil ich die Indirektion von den 2 Zeigern, die der Zugriff auf eine Rc<String> erfordert, reduzieren muss. Ich muss ein Rc verwenden, weil ich wirklich Besitz geteilt habe. Ich nähere Details in another question spezifischere Probleme, die ich um meinen Schnurtyp habe.Wie baue ich einen Rc <str> oder Rc <[T]>?

Rc has a ?Sized bound:

pub struct Rc<T: ?Sized> { /* fields omitted */ } 

ich auch habe gehört, dass Rust 1.2 wird zum Speichern unsized Typen in einem Rc mit dem richtigen Unterstützung kommen, aber ich bin nicht sicher, wie dies von 1,1 unterscheidet.

den str Fall als Beispiel nehmen, mein naive attempt (auch this für von einem String Gebäude) nicht mit:

use std::rc::Rc; 

fn main() { 
    let a: &str = "test"; 
    let b: Rc<str> = Rc::new(*a); 
    println!("{}", b); 
} 
error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied 
--> src/main.rs:5:22 
    | 
5 |  let b: Rc<str> = Rc::new(*a); 
    |      ^^^^^^^ `str` does not have a constant size known at compile-time 
    | 
    = help: the trait `std::marker::Sized` is not implemented for `str` 
    = note: required by `<std::rc::Rc<T>>::new` 

Es ist klar, dass, um ein Rc<str> zu schaffen, ich brauche das kopieren Ganzer String: RcBox wäre selbst ein unselisierter Typ, der den String selbst neben den schwachen und starken Zeigern speichert - der naive Code oben macht überhaupt keinen Sinn.

Mir wurde gesagt, dass man solche Art nicht instanziieren kann, sondern instanziieren Sie eine Rc<T> mit einer Größe T und dann zwingen Sie es zu einem unsized-Typ. Das angegebene Beispiel dient zum Speichern eines Merkmalsobjekts: Zuerst erstellen Sie Rc<ConcreteType> und dann erzwingen Sie Rc<Trait>. Aber das macht auch keinen Sinn: weder this noch this funktionieren (und Sie können nicht von &str oder String zu str sowieso zwingen).

+0

Da der Zugriff auf ein 'Rc ' erfordert, folgen Sie 2 Zeiger (auch, ich brauche 'Rc', weil ich wirklich die Eigentümerschaft geteilt habe). Ich erläutere [in einer anderen Frage] (https://stackoverflow.com/questions/31685345/is-there-a-rust-library-with-an-utf-16-string-type-intended-for-writing-a- Java) spezifischere Probleme, die ich mit meinem String-Typ habe. Meine vorläufige Definition 'Rc ' würde auch einen unsoziierten Typ 'Utf16Str' erfordern (es hätte das gleiche Layout wie' Rc <[u16]> '). – darque

+0

Siehe auch [Ist es möglich, einen Arc <[T\]> von einem Vec ?] (Https://stackoverflow.com/q/44636833/155423) zu erstellen. – Shepmaster

Antwort

9

Das Erstellen eines Rc<[T]> kann über Koerzitionen und as -Übertragungen von Arrays fester Größe, z. Nötigungen können getan werden, wie folgt:

use std::rc::Rc; 

fn main() { 
    let x: Rc<[i32; 4]> = Rc::new([1, 2, 3, 4]); 

    let y: Rc<[i32]> = x; 

    println!("{:?}", y); 
} 

Allerdings funktioniert das nicht für Streicher, da sie keine rohen feste Größe gleichwertig den ersten Wert zu schaffen. Es ist möglich, unsicher zu machen, z.B. durch Erstellen eines UTF-8-codierten Rc<[u8]> und Umwandeln dieses in Rc<str>. Theoretisch könnte es auf crates.io eine Kiste geben, aber ich kann im Moment keine finden.

Eine Alternative ist owning_ref, was nicht ganz std::rc::Rc selbst ist, sollte aber erlauben, beispielsweise eine RcRef<..., str> in eine Rc<String> zeigt bekommen. (Dieser Ansatz funktioniert am besten, wenn man RcRef gleichmäßig anstelle von Rc verwendet, außer für den Bau.)

extern crate owning_ref; 
use owning_ref::RcRef; 
use std::rc::Rc; 

fn main() { 
    let some_string = "foo".to_owned(); 

    let val: RcRef<String> = RcRef::new(Rc::new(some_string)); 

    let borrowed: RcRef<String, str> = val.map(|s| &**s); 

    let erased: RcRef<owning_ref::Erased, str> = borrowed.erase_owner(); 
} 

Der Lösch bedeutet, dass RcRef<..., str> s aus mehreren verschiedenen Quellen stammen kann, beispielsweise Eine RcRef<Erased, str> kann auch aus einem String-Literal kommen.

NB. zum Zeitpunkt des Schreibens, erfordert das Löschen mit RcRef einen nächtlichen Compiler, und je nach owning_ref mit dem nightly Feature:

[dependencies] 
owning_ref = { version = "0.1", features = ["nightly"] } 
+0

So ein 'Rc <[T]>' kann nicht erstellt werden, wenn die Länge von [T] zur Kompilierzeit unbekannt ist, oder? (Aber warum ist das? Ist 'Rc' nicht in dem Heap zugeordnet? Da es ein dicker Zeiger ist," weiß "es bereits seine Größe) – darque

+0

Ja, ein' Rc <[T]>' kann nicht über Zwang mit dynamischen Längen konstruiert werden. Allerdings macht das Konzept durchaus Sinn, das einzige blockierende Problem ist, dass es keinen guten Weg gibt, einen zu konstruieren. – huon

+0

Würde der Zugriff auf die 'Zeichenfolge' innerhalb von' RcRef' folgende zwei Zeiger erfordern? (Das ganze Problem ist, dass 'Rc ' einen Zeiger auf 'String' hat, der einen Zeiger auf den Anfang der Zeichenfolge hat ...). Ich kann nicht herausfinden, ob [this] (https://github.com/Kimundi/owning-ref-rs/blob/master/src/lib.rs#L178) nur einen Zeiger auf den 'String' hat. – darque

8

Ab Rust 1.21.0 und gemäß dem Mandat RFC 1845, ein Rc<str> oder Arc<str> ist nun möglich, die Schaffung:

use std::rc::Rc; 
use std::sync::Arc; 

fn main() { 
    let a: &str = "hello world"; 
    let b: Rc<str> = Rc::from(a); 
    println!("{}", b); 

    // or equivalently: 
    let b: Rc<str> = a.into(); 
    println!("{}", b); 

    // we can also do this for Arc, 
    let a: &str = "hello world"; 
    let b: Arc<str> = Arc::from(a); 
    println!("{}", b); 
} 

(Playground)

Siehe <Rc as From<&str>> und <Arc as From<&str>>.