I'd like to create an Rc<str>
because I want reduce the indirection from following the 2 pointers that accessing an Rc<String>
requires. I need to use an Rc
because I truly have shared ownership. I detail in another question more specific issues I have around my string type.
pub struct Rc<T: ?Sized> { /* fields omitted */ }
I've also heard that Rust 1.2 will come with proper support for storing unsized types in an Rc
, but I'm unsure how this differs from 1.1.
Taking the str
case as example, my naive attempt (also this for building from a String
) fails with:
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`
It's clear that in order to create an Rc<str>
, I need to copy the whole string: RcBox
would be itself an unsized type, storing the string itself alongside the weak and strong pointers — the naive code above doesn't even make sense.
I've been told that one can not instantiate such type, but instead instantiate an Rc<T>
with a sized T
and then coerce it to an unsized type. The example given is for the storing a trait object: first create Rc<ConcreteType>
and then coerce to Rc<Trait>
. But this doesn't make sense either: neither this nor this work (and you can't coerce from &str
or String
to str
anyway).
Creating an
Rc<[T]>
can be done via coercions andas
-casts from fixed sized arrays, e.g. coercions can be done as follows:However, this doesn't work for strings, since they have no raw fixed-sized equivalent to create the first value. It is possible to do unsafely, e.g. by creating a UTF-8 encoded
Rc<[u8]>
and transmuting that toRc<str>
. Theoretically there could be a crate on crates.io for it, but I can't find one at the moment.An alternative is
owning_ref
, which isn't quitestd::rc::Rc
itself, but should allow, for example, getting anRcRef<..., str>
pointing into anRc<String>
. (This approach will work best if one usesRcRef
uniformly in place ofRc
, except for construction.)The erasing means that
RcRef<..., str>
s can come from multiple different sources, e.g. aRcRef<Erased, str>
can come from a string literal too.NB. at the time of writing, the erasure with
RcRef
requires a nightly compiler, and depending onowning_ref
with thenightly
feature:As of Rust 1.21.0 and as mandated by RFC 1845, creating an
Rc<str>
orArc<str>
is now possible:(Playground)
See
<Rc as From<&str>>
and<Arc as From<&str>>
.