2015-07-28 8 views
13

Mi piacerebbe creare un Rc<str> perché voglio ridurre l'indirezione dal seguire i 2 puntatori che richiedono l'accesso a un Rc<String>. Devo usare uno Rc perché ho veramente condiviso la proprietà. I dettagli in another question più problemi specifici che ho intorno al mio tipo di stringa.Come costruire un Rc <str> o Rc <[T]>?

Rc has a ?Sized bound:

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

Ho anche sentito che Rust 1.2 sarà disponibile con un adeguato sostegno per la memorizzazione di tipo non calibrati in un Rc, ma io sono sicuro di come questo si differenzia da 1.1.

Prendendo il caso str come esempio, il mio naive attempt (anche this per la costruzione di un String) non riesce con:

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` 

E 'chiaro che, al fine di creare un Rc<str>, ho bisogno di copiare il tutta la stringa: RcBox sarebbe di per sé un tipo non standardizzato, che memorizza la stringa stessa accanto ai puntatori deboli e forti: l'ingenuo codice sopra non ha nemmeno senso.

Mi è stato detto che non è possibile creare un'istanza di questo tipo, ma creare un'istanza di Rc<T> con una dimensione T e quindi forzarla in un tipo non bloccato. L'esempio fornito è per la memorizzazione di un oggetto tratto: prima creare Rc<ConcreteType> e quindi forzare a Rc<Trait>. Ma questo non ha alcun senso: né lo this né lo this funzionano (e non è possibile forzare da &str o da String a str).

+0

Perché l'accesso a 'Rc ' richiede di seguire 2 puntatori (inoltre, ho bisogno di 'Rc' perché ho veramente condiviso la proprietà). Dettagli [in un'altra domanda] (https://stackoverflow.com/questions/31685345/is-there-a-rust-library-with-an-utf-16-string-type-intended-for-writing-a- java) problemi più specifici che ho intorno al mio tipo di stringa. La mia definizione provvisoria 'Rc ' richiederebbe anche un tipo non specificato 'Utf16Str' (avrebbe lo stesso layout di' Rc <[u16]> '). – darque

+0

Vedere anche [È possibile creare un Arc <[T\]> da un Vec ?] (Https://stackoverflow.com/q/44636833/155423). – Shepmaster

risposta

9

Creazione di un Rc<[T]> può essere eseguito tramite coercizione e as -casts da matrici di dimensioni fisse, ad es. coercizioni può essere fatto nel modo seguente:

use std::rc::Rc; 

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

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

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

Tuttavia, questo non funziona per le stringhe, dal momento che non hanno equivalenti grezzo fisso di dimensioni per creare il primo valore. È possibile fare in modo non sicuro, ad es. creando una codifica UTF-8 Rc<[u8]> e trasmettendola a Rc<str>. Teoricamente potrebbe esserci una cassa in casse.io per questo, ma al momento non riesco a trovarne una.

Un'alternativa è owning_ref, che non è del tutto std::rc::Rc in sé, ma dovrebbe consentire, ad esempio, ottenere un RcRef<..., str> indicando in un Rc<String>. (Questo approccio funziona meglio se si usa RcRef uniformemente in luogo di Rc, tranne per la costruzione.)

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

La cancellazione significa che RcRef<..., str> s possono provenire da molteplici fonti diverse, ad esempio un RcRef<Erased, str> può provenire anche da una stringa letterale.

NB. al momento della scrittura, la cancellazione con RcRef richiede un compilatore notturno e seconda owning_ref con la funzione nightly:

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

Quindi un 'Rc <[T]>' non può essere creato quando la lunghezza di [T] è sconosciuta al momento della compilazione, giusto? (Ma perché? Non è 'Rc' allocato nell'heap? Poiché è un puntatore grasso già" conosce "le sue dimensioni) – darque

+0

Sì, un' Rc <[T]> 'non può essere costruito tramite coercizione con lunghezze dinamiche. Tuttavia, il concetto ha assolutamente senso, l'unico problema di blocco è che non esiste un buon modo per costruirne uno. – huon

+0

Inoltre, l'accesso a 'String' all'interno di' RcRef' richiede di seguire due punti? (L'intero problema è che 'Rc ' ha un puntatore a 'String' che ha un puntatore all'inizio della stringa ...). Non riesco a capire se [questo] (https://github.com/Kimundi/owning-ref-rs/blob/master/src/lib.rs#L178) abbia un puntatore a 'String'. – darque

8

Al ruggine 1.21.0 e come previsto dalla RFC 1845, creando un Rc<str> o Arc<str> è ora possibile:

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)

Vedi <Rc as From<&str>> e <Arc as From<&str>>.

Problemi correlati