gpt4 book ai didi

rust - Rc 到 Option

转载 作者:行者123 更新时间:2023-11-29 08:03:55 26 4
gpt4 key购买 nike

我正在尝试实现如下所示的方法:

fn concretify<T: Any>(rc: Rc<Any>) -> Option<T> {
Rc::try_unwrap(rc).ok().and_then(|trait_object| {
let b: Box<Any> = unimplemented!();
b.downcast().ok().map(|b| *b)
})
}

然而,try_unwrap不适用于特征对象(这是有道理的,因为它们没有大小)。我的下一个想法是尝试找到一些解包 Rc<Any> 的函数。进入Box<Any>直接地。我能找到的最接近的东西是

if Rc::strong_count(&rc) == 1 {
Some(unsafe {
Box::from_raw(Rc::into_raw(rc))
})
} else {
None
}

然而,Rc::into_raw()似乎要求 Rc 中包含的类型成为Sized , 理想情况下我不想使用 unsafe block 。

有什么办法可以实现吗?

Playground Link ,我正在寻找 rc_to_box 的实现在这里。

最佳答案

不幸的是,似乎 Rc 的 API当它是 !Sized 时,缺少能够获得包装类型所有权的必要方法.

唯一可能返回 Rc 内部项目的方法是Rc::try_unwrap ,但是它返回 Result<T, Rc<T>>这需要 TSized .

为了做你想做的事,你需要一个带有签名的方法:Rc<T> -> Result<Box<T>, Rc<T>> , 这将允许 T成为!Sized , 从那里你可以提取 Box<Any>并执行 downcast打电话。

但是,由于Rc,这种方法是不可能的实现。这是 Rc 的精简版:

struct RcBox<T: ?Sized> {
strong: Cell<usize>,
weak: Cell<usize>,
value: T,
}

pub struct Rc<T: ?Sized> {
ptr: *mut RcBox<T>,
_marker: PhantomData<T>,
}

因此,只有Box你可以离开Rc<T>Box<RcBox<T>> .

请注意,此处的设计受到严格限制:

  • 单一分配要求所有 3 个元素都在一个 struct
  • T: ?Sized要求 T成为最后一个领域

所以总的来说,改进的空间很小。


但是,在您的具体情况下,绝对有可能改进一般情况。当然,它确实需要 unsafe代码。虽然它与 Rc 配合得很好, 用 Arc 实现它可能会因潜在的数据竞争而变得复杂。

哦...并且代码按原样提供,不暗示任何保证;)

use std::any::Any;
use std::{cell, mem, ptr};
use std::rc::Rc;

struct RcBox<T: ?Sized> {
strong: cell::Cell<usize>,
_weak: cell::Cell<usize>,
value: T,
}

fn concretify<T: Any>(rc: Rc<Any>) -> Option<T> {
// Will be responsible for freeing the memory if there is no other weak
// pointer by the end of this function.
let _guard = Rc::downgrade(&rc);

unsafe {
let killer: &RcBox<Any> = {
let killer: *const RcBox<Any> = mem::transmute(rc);
&*killer
};

if killer.strong.get() != 1 { return None; }

// Do not forget to decrement the count if we do take ownership,
// as otherwise memory will not get released.
let result = killer.value.downcast_ref().map(|r| {
killer.strong.set(0);
ptr::read(r as *const T)
});

// Do not forget to destroy the content of the box if we did not
// take ownership
if result.is_none() {
let _: Rc<Any> = mem::transmute(killer as *const RcBox<Any>);
}

result
}
}

fn main() {
let x: Rc<Any> = Rc::new(1);
println!("{:?}", concretify::<i32>(x));
}

关于rust - Rc<Trait> 到 Option<T>?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41618100/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com