将&amp; Type替换为&amp; Wrapper <type>

时间:2016-12-27 10:43:23

标签: rust

我有一个值的引用,我想用一个包含该值的包装器结构的引用替换它。

示例:

struct Wrapper<T>(T);

let num = 123;
let x: &i32 = &num;
let wrapped: &Wrapper<i32> = .. // some conversion

这可能吗? (安全解决方案是首选,但不是必需的。)

2 个答案:

答案 0 :(得分:2)

使示例代码很容易实现:

let wrapped: &Wrapper<i32> = &Wrapper(*x);    // type annotation optional

来自C ++,您可能认为这是疯狂的不安全因为我们引用了一个临时(左侧的表达式)。但在这种情况下,Rust只会将此临时表达式的结果保存在堆栈中。上面的代码相当于:

let hidden = Wrapper(*x);
let wrapped: &Wrapper = &hidden;

到目前为止一直很好,但是当我们想要返回此引用时会出现问题。例如:

fn wrap<T>(t: &T) -> &Wrapped<T> {
    &Wrapped(*t)
}

我们这里有两个问题。首先,我们不能离开t(它只是借用;它只在上面的代码中起作用,因为i32Copy),其次,我们不能返回一个局部变量(为我们创建的hidden)。

要解决此问题,您可以使用unsafe函数std::mem::transmute()。这只是将任何类型解释为另一种类型。

但是等等! unsafe {}表示“编译器,相信我!”,但我们应该相信自己吗?作为程序员,我们必须保证Wrapped<T>T具有完全相同的数据布局。那么:就是这样吗?

在大多数平台上可能都是这样,但我非常怀疑我们可以保证这一点!在结构(和单元结构)的数据布局方面,Rust似乎没有多少承诺。它可能会重新排序字段(在这种情况下不重要)并可能添加填充。 repr(Rust) chapter of the Rustonomicon中有更多相关信息。

总结wrap() 等功能无法安全实施。因此,应避免使用包含此类功能的API。

答案 1 :(得分:1)

您不需要任何转换;你可以通过以下方式实现这一目标:

#[derive(Debug)]
struct Wrapper(i32);

let num = 123; // the value
let x = &num; // the reference to the value
let wrapped: Wrapper = Wrapper(*x); // now you can refer to &wrapped

println!("{:?}", wrapped);