如何构建 Rc<str>还是Rc [T] ? [英] How to build an Rc<str> or Rc<[T]>?
问题描述
我想创建一个 Rc
因为我想减少访问 Rc
所需的 2 个指针的间接性.我需要使用 Rc
因为我确实拥有共享所有权.我在 另一个问题 我对我的字符串类型有更具体的问题.
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.
Rc 有一个 ?Sized
绑定:
Rc has a ?Sized
bound:
pub struct Rc<T: ?Sized> { /* fields omitted */ }
我还听说 Rust 1.2 将适当支持在 Rc
中存储未确定大小的类型,但我不确定这与 1.1 有何不同.
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.
以 str
为例,我的 天真的尝试(也这个用于从String
) 失败:
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`
很明显,为了创建一个 Rc
,我需要复制整个字符串:RcBox
本身就是一个未定义大小的类型,存储字符串本身除了弱指针和强指针——上面的代码甚至没有任何意义.
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.
我被告知不能实例化这样的类型,而是用一个大小的 T
实例化一个 Rc
,然后将其强制为一个非大小的类型.给出的例子是存储一个 trait 对象:首先创建 Rc
然后强制转换为 Rc
.但这也没有意义:this 和 &str
或 String
到 str
无论如何).
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).
推荐答案
创建一个 Rc<[T]>
可以通过强制转换和 as
-casts from固定大小的数组,例如可以通过以下方式进行强制转换:
Creating an Rc<[T]>
can be done via coercions and as
-casts from fixed sized arrays, e.g. coercions can be done as follows:
use std::rc::Rc;
fn main() {
let x: Rc<[i32; 4]> = Rc::new([1, 2, 3, 4]);
let y: Rc<[i32]> = x;
println!("{:?}", y);
}
然而,这不适用于字符串,因为它们没有原始固定大小的等价物来创建第一个值.有可能不安全地做,例如通过创建 UTF-8 编码的 Rc<[u8]>
并将其转换为 Rc
.从理论上讲,crates.io 上可能有一个 crate,但我目前找不到.
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 to Rc<str>
. Theoretically there could be a crate on crates.io for it, but I can't find one at the moment.
另一种选择是owning_ref
,它不太std::rc::Rc
本身,但应该允许,例如,获取一个 RcRef<..., str>
指向一个 Rc
>.(这种方法最好使用 RcRef
代替 Rc
,除了构造.)
An alternative is owning_ref
, which isn't quite std::rc::Rc
itself, but should allow, for example, getting an RcRef<..., str>
pointing into an Rc<String>
. (This approach will work best if one uses RcRef
uniformly in place of Rc
, except for construction.)
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();
}
擦除意味着 RcRef<..., str>
s 可以来自多个不同的来源,例如RcRef
也可以来自字符串文字.
The erasing means that RcRef<..., str>
s can come from multiple different sources, e.g. a RcRef<Erased, str>
can come from a string literal too.
注意.在撰写本文时,使用 RcRef
进行擦除需要夜间编译器,并且依赖于具有 nightly
功能的 owning_ref
:
NB. at the time of writing, the erasure with RcRef
requires a nightly compiler, and depending on owning_ref
with the nightly
feature:
[dependencies]
owning_ref = { version = "0.1", features = ["nightly"] }
这篇关于如何构建 Rc<str>还是Rc [T] ?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!