Deref struct to tuple需要移动

时间:2017-09-06 18:13:54

标签: rust dereference

我正在写一个Vector类只是为了生锈,并认为能够为它实现Deref会很好,就像一个元组引用一样访问它。 例如,Vec2<f32>可以取消引用为&(f32, f32)。 我想出了这个:

pub struct Vec2<T> {
    pub x: T,
    pub y: T
}

impl<T> Deref for Vec2<T> {
    type Target = (T, T);

    fn deref(&self) -> &(T, T) {
        &(self.x, self.y)
    }
}

但是,由于编译器想要创建元组然后引用它,它会尝试 离开结构。 如果我使用type Target = (&T, &T)然后返回&(&T, &T),我必须使用明确的生命周期说明符,因为我无法访问自我生命期,所以我不会这样做。

现在我的问题是:有没有办法在不复制值的情况下执行此操作?由于我经常使用小型,我可能不会真正使用Deref,但DerefMut可能会变得有用,我想象。

1 个答案:

答案 0 :(得分:1)

摘要

现在,没有办法做到这一点!至少没有使用unsafe

为什么?

考虑返回类型-> &Foo。这意味着该函数返回对已存在于某处的Foo的引用。特别是,如果您有fn deref(&self) -> &Foo,则表示Foo的生命至少与self一样长,因为生命周期缩减会将其转换为fn deref<'a>(&'a self) -> &'a Foo

现在,(T, T)就像Foo一样。因此fn deref(&self) -> &(T, T)表示您返回对已经存在于某处的T元组的引用。但是没有这样的元组!你可以在函数中创建一个元组,但这不会长久存在。同样,如果您说-> &(&T, &T),则表示您返回对已存在于某处的元组(引用T)的引用。但是又一次:你没有一个元组已经存在于某个地方。

因此,特征Deref要求您返回对已经与self中的内容完全相同的内容的引用。所以有了这个,就不可能做你想做的事。

不安全

您可以使用不安全的函数mem::transmute()。毕竟,像你的结构和元组应该具有完全相同的内存布局,对吧?

是和否。两种内存布局可能都是相同的,但Rust并不能保证! Rust可以自由重新排序字段并添加填充字节。虽然我怀疑结构,元组结构和元组的内存布局完全相同,但我找不到源代码。因此,如果没有规范中的信息,转化在技术上是不安全的。

未来

将来,HKT或更多通用关联类型可以解决这个问题。也就是说,它们不会直接解决您的问题,但是根据this RFC中定义的GAT,可以重新定义Deref特征。那就是:

trait Deref {
    type Target<'a>;
    fn deref(&self) -> Self::Target<'a>;
}

现在我们被迫将生命“置于最外层”。有了这个,我们可以让实现Deref的类型决定。在这种情况下,你可以写:

impl<T> Deref for Vec2<T> {
    type Target<'a> = (&'a T, &'a T);

    fn deref(&self) -> Self::Target {
        (&self.x, &self.y)
    }
}

这样,生命就在“内在”。

但GAT尚未实施,因此仍需要一些时间。此外,还不清楚标准库何时/如何/如何以向后不兼容的方式更改,以允许更改Deref