我正在创建一个函数,该函数返回对特征对象的Weak
引用。在无法找到对象的情况下(它是查找函数),我想使用Weak
返回空的Weak::new()
引用:
use std::rc::{self, Rc, Weak};
use std::cell::RefCell;
pub trait Part {}
pub struct Blah {}
impl Part for Blah {}
fn main() {
let blah = Blah {};
lookup(Rc::new(RefCell::new(blah)));
}
fn lookup(part: Rc<RefCell<Part>>) -> Weak<RefCell<Part>> {
if true {
Rc::downgrade(&part)
} else {
Weak::new()
}
}
编译期间出现以下错误:
error[E0277]: the trait bound `Part + 'static: std::marker::Sized` is not satisfied in `std::cell::RefCell<Part + 'static>`
--> <anon>:19:9
|
19 | Weak::new()
| ^^^^^^^^^ within `std::cell::RefCell<Part + 'static>`, the trait `std::marker::Sized` is not implemented for `Part + 'static`
|
= note: `Part + 'static` does not have a constant size known at compile-time
= note: required because it appears within the type `std::cell::RefCell<Part + 'static>`
= note: required by `<std::rc::Weak<T>>::new`
为什么我可以从Weak<RefCell<Part>>
成功创建Rc::downgrade()
但不能使用相同的类型来创建Weak::new()
的新弱引用?
我有没有办法注释Weak::new()
来帮助编译器,还是我必须将它包装在Option
中以让用户知道找不到该部分?
答案 0 :(得分:4)
Weak::new()
推断的类型为Weak<RefCell<Part>>
,无法创建Part
部分,因为它是一个特征!
Sized
错误的全部内容。特性不是一个具体的结构,它在编译时没有已知的大小,因此编译器不知道要分配多少空间。
为什么我可以从
成功创建Weak<RefCell<Part>>
Rc::downgrade()
这是因为Rc<RefCell<Part>>
指向已经分配的结构。编译器可以使用特征指针引用它,即使它不知道它是Blah
还是Part
特征的其他实现。
我有没有办法注释
Weak::new()
来帮助编译器
您确实可以注释Weak::new()
,将编译器指向您想要实例化的Part
实现,如下所示:
use std::rc::{Rc, Weak};
use std::cell::RefCell;
pub trait Part {}
pub struct Blah {}
impl Part for Blah {}
fn main() {
let blah = Blah {};
lookup(Rc::new(RefCell::new(blah)));
}
fn lookup(part: Rc<RefCell<Part>>) -> Weak<RefCell<Part>> {
if true {
Rc::downgrade(&part)
} else {
Weak::<RefCell<Blah>>::new()
}
}
答案 1 :(得分:2)
TL; DR:胖指针很难。
因此,您需要在强制实施之前明确指定具体类型:
Weak::<RefCell<Blah>>::new()
注意:如果Blah
占用大量内存,请创建零大小类型Fool
,为其实现Part
(所有函数unimplemented!()
),然后使用Weak::<RefCell<Fool>>::new()
来避免无用地分配内存。
我认为潜在的问题只是实施问题之一。
它似乎不可修复,但可能需要相当多的工作来涵盖所有极端情况。
首先,让我们揭露问题。
Weak::new
的实施:
impl<T> Weak<T> {
pub fn new() -> Weak<T> {
unsafe {
Weak {
ptr: Shared::new(Box::into_raw(box RcBox {
strong: Cell::new(0),
weak: Cell::new(1),
value: uninitialized(),
})),
}
}
}
}
对于同质性,所有Shared
元素都包含RcBox
,其中包含两个Cell
(计数器)和实际值。
构建RcBox<T>
这一事实需要知道T
的大小,这就是为什么与大多数Weak
方法不同,{{1}在此T
中未标记为: ?Sized
。
现在,由于内存未被初始化,很明显它永远不会被使用,所以实际任何大小都没问题。
impl
实际上可以携带未经过身份验证的数据,这是RcBox
到RcBox<Struct>
所必需的,因此RcBox<Trait>
和{{ 1}}字段总是先布置 (只有最后一个字段可以不用)。
因此,我们希望
strong
,这样可以节省内存并且不需要weak
为RcBox<()>
,T
,无论Sized
是什么。好的,让我们做吧!
我们期望的实现将如下所示:
RcBox<T>
完全无法编译。
为什么呢?因为T
是精简指针,而impl<T: ?Sized> Weak<T> {
pub fn new() -> Weak<T> {
unsafe {
Weak {
ptr: Shared::new(transmute(Box::into_raw(box RcBox {
strong: Cell::new(0),
weak: Cell::new(1),
value: (),
}))),
}
}
}
}
是精简指针或胖指针(see raw memory representation),取决于*mut RcBox<()>
是*mut RcBox<T>
还是{{} 1}}。
现在,特征指针can be handled(警告:包含T
的简化且完全不安全的实现),以及Sized
的以下实现:
!Sized
然而,这个实现只考虑特征指针,还有其他类型的胖指针,它可能会完全崩溃。