首页 > 解决方案 > 如何返回对添加到特征对象向量中的具体类型的引用?

问题描述

在这段代码中,我获取一个向量,创建一个结构实例,并将其添加到装箱的向量中:

trait T {}

struct X {}
impl T for X {}

fn add_inst(vec: &mut Vec<Box<T>>) -> &X {
    let x = X {};
    vec.push(Box::new(x));
    // Ugly, unsafe hack I made
    unsafe { std::mem::transmute(&**vec.last().unwrap()) }
}

显然,它使用mem::transmute,这让我觉得这不是正确的方法。这个丑陋的黑客是唯一的方法吗?

此外,虽然它在 Rust 1.32 中编译,但在 Rust 1.34 中失败:

error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
  --> src/lib.rs:10:14
   |
10 |     unsafe { std::mem::transmute(&**vec.last().unwrap()) }
   |              ^^^^^^^^^^^^^^^^^^^
   |
   = note: source type: `&dyn T` (128 bits)
   = note: target type: `&X` (64 bits)

标签: vectorrust

解决方案


我认为这段代码是安全的:

fn add_inst(vec: &mut Vec<Box<dyn T>>) -> &X {
    let x = X {};
    let b = Box::new(x);
    let ptr = &*b as *const X;
    vec.push(b);
    unsafe { &*ptr }
}

诀窍是在将原始指针*const X转换为Box<dyn T>. 然后,您可以在从函数返回之前将其转换回引用。这是安全的,因为一个装箱的值永远不会移动,(当然,除非它移出Box),所以在into的转换中ptr幸存下来。bBox<dyn T>


推荐阅读