Rust 将结构解除到元组需要移动

Rust 将结构解除到元组需要移动,rust,dereference,Rust,Dereference,我写一个向量类只是为了在rust中找点乐子,我认为能够为它实现Deref会很好,就像元组引用一样访问它。 例如,Vec2可以作为和(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,

我写一个向量类只是为了在rust中找点乐子,我认为能够为它实现Deref会很好,就像元组引用一样访问它。 例如,
Vec2
可以作为
和(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)
    }
}
pub-struct-Vec2{
酒吧x:T,
酒吧y:T
}
Vec2的impl-Deref{
类型目标=(T,T);
fn deref(和self)->和(T,T){
&(self.x,self.y)
}
}
但是,由于编译器希望创建元组并引用它,因此它会尝试 移出结构。 如果我使用
typetarget=(&T,&T)
返回
&(&T,&T)
我必须使用显式生命周期说明符,因为我无法访问自身生命周期,所以我没有显式生命周期说明符

现在我的问题是:有没有一种不复制值的方法?因为我经常使用小型类型,所以无论如何我可能不会真正使用Deref,但我想DerefMut可能会变得有用。

Summary 现在,没有办法做到这一点至少在不使用
不安全的情况下是这样


为什么? 考虑返回类型
->&Foo
。这意味着该函数返回对某个已存在的
Foo
的引用。特别是,如果您有
fn-deref(&self)->&Foo
,这意味着
Foo
的寿命至少与
self
的寿命一样长,因为生命周期省略将起作用并将其转换为
fn-deref&'a Foo

现在,
(T,T)
是一种类似于
Foo
的类型。因此,
fn deref(&self)->&(T,T)
意味着您返回对已经存在于某处的
T
s元组的引用。但是没有这样的元组!您可以在函数中创建一个元组,但这不会持续足够长的时间。类似地,如果你说
->&(&T,&T)
,你说你返回了一个对元组(reference to
T
)的引用,这个元组已经存在于某个地方。但再一次:你没有一个元组已经住在某个地方了

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

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

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

未来 将来,HKTs或更通用的关联类型可以解决这个问题。也就是说,它们不会直接解决您的问题,但是使用GATs,如中所定义的,可以重新定义
Deref
特性。即:

trait Deref {
    type Target<'a>;
    fn deref(&self) -> Self::Target<'a>;
}
这样,生命就“在里面”


但《服务贸易总协定》甚至还没有实施,因此还需要一段时间。此外,还不清楚标准库何时/如何/是否以向后不兼容的方式更改,这将允许更改
Deref

我不知道HKT/ATC将来将如何解决这个问题?@kennytm我编辑了我的答案来解释这句话。我希望这能让事情变得更清楚。我明白了。虽然这产生的仍然是
(&T,&T)
,而不是
&(T,T)
。我不确定
&(T,T)
是否可能,除非编译器对元组和结构使用相同的布局。这是合理的,但是idk如果由语言语义保证的话。
impl<T> Deref for Vec2<T> {
    type Target<'a> = (&'a T, &'a T);

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