2015-07-28 5 views
13

Chciałbym utworzyć Rc<str>, ponieważ chcę zmniejszyć niedokładność z następujących 2 wskaźników, które wymagają dostępu do Rc<String>. Muszę użyć Rc, ponieważ naprawdę mam wspólną własność. Szczegółowo opisuję w another question bardziej szczegółowe problemy, które mam wokół mojego typu ciągu.Jak zbudować Rc ​​<str> lub Rc <[T]>?

Rc has a ?Sized bound:

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

Słyszałem również, że Rust 1,2 przyjdzie z odpowiednim wsparciem dla przechowywania niezagruntowanej typy w Rc, ale jestem pewien sposób różni się od 1.1.

Biorąc sprawę str jako przykład, mój naive attempt (również this na budowę od String) nie powiedzie się z:

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` 

To jasne, że w celu stworzenia Rc<str>, muszę skopiować cały ciąg: RcBox byłby sam w sobie niezsynchronizowanym typem, przechowującym strunę obok słabych i mocnych wskaźników - powyższy naiwny kod nie ma nawet sensu.

Powiedziano mi, że nie można utworzyć tego typu, ale zamiast tego należy utworzyć instancję Rc<T> o rozmiarze T, a następnie przymusić ją do typu niezmienionego. Podany przykład dotyczy przechowywania obiektu cechy: najpierw stwórz Rc<ConcreteType>, a następnie przymuszaj do Rc<Trait>. Ale to też nie ma sensu: ani this, anidziałać (i nie można przymuszać z &str lub String do str tak).

+0

Ponieważ dostęp do 'Rc ' wymaga następujących 2 wskaźników (również, potrzebuję 'Rc', ponieważ naprawdę mam współwłasność). Szczegółowo [w innym pytaniu] (https://stackoverflow.com/questions/31685345/is-there-a-rust-library-with-an-utf-16-tring-type-intended- forwriting-a- java) bardziej szczegółowe problemy Mam wokół mojego typu ciąg. Moja wstępna definicja "Rc " również wymagałaby typu niezmienionego 'Utf16Str' (miałaby taki sam układ jak' Rc <[u16]> '). – darque

+0

Zobacz także [Czy jest możliwe utworzenie łuku <[T\]> z Vec ?] (Https://stackoverflow.com/q/44636833/155423). – Shepmaster

Odpowiedz

9

Utworzenie Rc<[T]> można wykonać za pomocą przymusu i odczytów as z tablic o ustalonych rozmiarach, np. coercions Można to zrobić w następujący sposób:

use std::rc::Rc; 

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

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

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

Jednak to nie działa dla ciągów, ponieważ nie mają one surowe stałe wielkości ekwiwalentu, aby utworzyć pierwszą wartość. Można robić niefajnie, np. tworząc kodowany UTF-8 Rc<[u8]> i transmutujący go do Rc<str>. Teoretycznie może to być skrzynka na crates.io, ale w tej chwili nie mogę jej znaleźć.

Alternatywą jest owning_ref, co nie jest zupełnie sama std::rc::Rc, ale powinna pozwalać na przykład uzyskanie RcRef<..., str> wskazując na w Rc<String>. (To podejście działa najlepiej jeśli używa RcRef równomiernie zamiast Rc wyjątkiem konstrukcji.)

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

Kasowanie oznacza RcRef<..., str> y mogą pochodzić z wielu różnych źródeł, np a RcRef<Erased, str> może pochodzić również z literału.

NB. w czasie pisania, wymazywanie z RcRef wymaga nocne kompilator, w zależności od owning_ref z funkcją nightly:

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

Tak więc 'Rc <[T]>' nie można utworzyć, gdy długość [T] jest nieznana podczas kompilacji, prawda? (Ale dlaczego tak jest ?, czy '' Rc' nie jest przydzielony w stercie ?, ponieważ jest to gruby wskaźnik, który już "zna" jego rozmiar) – darque

+0

Tak, 'Rc <[T]>' nie może być skonstruowany przez wymuszenie z dynamicznymi długościami. Jednak koncepcja ta ma całkowicie sens, jedynym problemem blokującym jest to, że nie ma dobrego sposobu na jej zbudowanie. – huon

+0

Również dostęp do 'String' wewnątrz' RcRef' wymaga następujących dwóch wskaźników? (cały problem polega na tym, że 'Rc ' ma wskaźnik do 'String', który ma wskaźnik na początku łańcucha ...). Nie mogę się dowiedzieć, czy [this] (https://github.com/Kimundi/owning-ref-rs/blob/master/src/lib.rs#L178) ma tylko wskaźnik do 'String'. – darque

8

As of Rust 1.21.0 i zgodnie z zaleceniami RFC 1845, tworząc Rc<str> lub Arc<str> jest teraz możliwe:

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)

Patrz <Rc as From<&str>> i <Arc as From<&str>>.

Powiązane problemy