Deref struct to tuple 需要移动
Deref struct to tuple requires move
我正在编写一个 Vector class 只是为了在 Rust 中获得乐趣,并且认为能够为它实现 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)
然后 return a &(&T, &T)
我将不得不使用明确的生命周期说明符,我没有,因为我无法访问自我生命周期。
现在我的问题是:有没有一种方法可以在不复制值的情况下做到这一点?由于我经常使用小型类型,所以我可能不会真正使用 Deref,但我想 DerefMut 可能会变得有用。
总结
现在,没有办法做到这一点! 至少没有使用 unsafe
。
为什么?
考虑 return 类型 -> &Foo
。这意味着函数 return 是对已经存在于某处的 Foo
的引用。特别是,如果您有 fn deref(&self) -> &Foo
,则意味着 Foo
至少与 self
一样长,因为生命周期省略开始并将其转换为 fn deref<'a>(&'a self) -> &'a Foo
。
现在,(T, T)
和 Foo
一样是一个类型。所以 fn deref(&self) -> &(T, T)
意味着你 return 对已经存在于某处的 T
的元组的引用。但是没有这样的元组!您可以在函数中创建一个元组,但这不会存在足够长的时间。类似地,如果你说 -> &(&T, &T)
你说你 return 对已经存在于某处的(对 T
的引用)的元组的引用。但同样:你没有一个元组已经存在于某个地方。
所以特征 Deref
要求你 return 引用已经与 self
中完全一样的东西。所以有了这个,就不可能做你想做的事。
不安全
您可以使用不安全函数 mem::transmute()
。毕竟,像您这样的结构和元组应该具有完全相同的内存布局,对吧?
是也不是。两种内存布局可能是相同的,但 Rust 不保证! Rust 可以自由地重新排序字段和添加填充字节。虽然我怀疑结构、元组结构和元组的内存布局完全相同,但我找不到相关资料。因此,如果规范中没有该信息,转换在技术上是不安全的。
未来
将来,HKT 或更确切地说是泛型关联类型可以解决这个问题。也就是说,它们不会直接解决您的问题,但是使用 this RFC 中定义的 GAT,可以重新定义 Deref
特征。即:
trait Deref {
type Target<'a>;
fn deref(&self) -> Self::Target<'a>;
}
现在我们被迫放置生命周期 "at the outermost level"。有了这个,我们可以让实现 Deref
的类型来决定。在那种情况下你可以写:
impl<T> Deref for Vec2<T> {
type Target<'a> = (&'a T, &'a T);
fn deref(&self) -> Self::Target {
(&self.x, &self.y)
}
}
这样寿命是"on the inside".
但是GAT还没有实现,所以还需要一些时间。此外,尚不清楚 when/how/if 标准库是否以向后不兼容的方式更改,这将允许更改 Deref
.
我正在编写一个 Vector class 只是为了在 Rust 中获得乐趣,并且认为能够为它实现 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)
然后 return a &(&T, &T)
我将不得不使用明确的生命周期说明符,我没有,因为我无法访问自我生命周期。
现在我的问题是:有没有一种方法可以在不复制值的情况下做到这一点?由于我经常使用小型类型,所以我可能不会真正使用 Deref,但我想 DerefMut 可能会变得有用。
总结
现在,没有办法做到这一点! 至少没有使用 unsafe
。
为什么?
考虑 return 类型 -> &Foo
。这意味着函数 return 是对已经存在于某处的 Foo
的引用。特别是,如果您有 fn deref(&self) -> &Foo
,则意味着 Foo
至少与 self
一样长,因为生命周期省略开始并将其转换为 fn deref<'a>(&'a self) -> &'a Foo
。
现在,(T, T)
和 Foo
一样是一个类型。所以 fn deref(&self) -> &(T, T)
意味着你 return 对已经存在于某处的 T
的元组的引用。但是没有这样的元组!您可以在函数中创建一个元组,但这不会存在足够长的时间。类似地,如果你说 -> &(&T, &T)
你说你 return 对已经存在于某处的(对 T
的引用)的元组的引用。但同样:你没有一个元组已经存在于某个地方。
所以特征 Deref
要求你 return 引用已经与 self
中完全一样的东西。所以有了这个,就不可能做你想做的事。
不安全
您可以使用不安全函数 mem::transmute()
。毕竟,像您这样的结构和元组应该具有完全相同的内存布局,对吧?
是也不是。两种内存布局可能是相同的,但 Rust 不保证! Rust 可以自由地重新排序字段和添加填充字节。虽然我怀疑结构、元组结构和元组的内存布局完全相同,但我找不到相关资料。因此,如果规范中没有该信息,转换在技术上是不安全的。
未来
将来,HKT 或更确切地说是泛型关联类型可以解决这个问题。也就是说,它们不会直接解决您的问题,但是使用 this RFC 中定义的 GAT,可以重新定义 Deref
特征。即:
trait Deref {
type Target<'a>;
fn deref(&self) -> Self::Target<'a>;
}
现在我们被迫放置生命周期 "at the outermost level"。有了这个,我们可以让实现 Deref
的类型来决定。在那种情况下你可以写:
impl<T> Deref for Vec2<T> {
type Target<'a> = (&'a T, &'a T);
fn deref(&self) -> Self::Target {
(&self.x, &self.y)
}
}
这样寿命是"on the inside".
但是GAT还没有实现,所以还需要一些时间。此外,尚不清楚 when/how/if 标准库是否以向后不兼容的方式更改,这将允许更改 Deref
.