为类型参数传递 Rust 生命周期
Communicating Rust Lifetimes for Type Parameters
我正在处理一个简单的复数示例,并尝试按如下方式实现 ref-value/value-ref 操作:
use std::ops::*;
#[derive(Clone, PartialEq)]
pub struct Complex<T: Sized + Clone> {
pub re: T,
pub im: T,
}
// Ref-Ref Multiplication
impl<'a, 'b, T: Sized + Clone> Mul<&'b Complex<T>> for &'a Complex<T>
where
T: Add<T, Output = T>,
T: Sub<T, Output = T>,
&'a T: Add<&'b T, Output = T>,
&'a T: Mul<&'b T, Output = T>,
&'a T: Sub<&'b T, Output = T>,
{
type Output = Complex<T>;
fn mul(self, rhs: &'b Complex<T>) -> Complex<T> {
panic!("// Details irrelevant")
}
}
// Ref-Value Multiplication
impl<'a, 'b, T: Sized + Clone> Mul<Complex<T>> for &'a Complex<T>
where
T: 'static,
T: Add<T, Output = T>,
T: Sub<T, Output = T>,
&'a T: Add<&'b T, Output = T>,
&'a T: Mul<&'b T, Output = T>,
&'a T: Sub<&'b T, Output = T>,
{
type Output = Complex<T>;
fn mul(self, rhs: Complex<T>) -> Complex<T> {
let t = &rhs;
self.mul(t)
}
}
ref-ref 实现有效,据我了解,它接受两个不同生命周期的引用,returns 一个复杂的值类型。参考值部分是我遇到问题的地方;当我编译时,错误是 rhs
的寿命不够长。我相信我已经知道为什么会这样了,那就是 T 可以在返回值时持有对 rhs 的引用(直接或间接),因此 rhs
超出范围,但 T
可以仍然保留对它的引用。
我的问题是如何传达 T
不会以某种形式或形式引用 rhs
。
关于我迄今为止尝试过或看过的事情的一些注释:
- 更改了任一 Mul 实现的生命周期规范。
- 尝试了生命周期继承,但这指定了
T
持有的引用将至少与 T
一样长,所以我想我需要在 [=34= 行中添加更多内容]
- 查看了其他实现;要么没有实现案例,要么只是使用克隆来绕过问题。
正如 Peter Hall 在评论中所建议的那样,最简单的解决方案是为您的复杂类型派生 Copy
,并实现值的操作。对于 ref-ref 实现和 ref-val 实现,您可以简单地取消引用引用并使用 val-val 实现。
如果你想让你开始的方法起作用,你需要更高等级的特征边界:
use std::ops::*;
#[derive(Clone, PartialEq)]
pub struct Complex<T: Clone> {
pub re: T,
pub im: T,
}
// Ref-Ref Multiplication
impl<'a, 'b, T: Clone> Mul<&'b Complex<T>> for &'a Complex<T>
where
T: Add<T, Output = T>,
T: Sub<T, Output = T>,
&'a T: Add<&'b T, Output = T>,
&'a T: Mul<&'b T, Output = T>,
&'a T: Sub<&'b T, Output = T>,
{
type Output = Complex<T>;
fn mul(self, rhs: &'b Complex<T>) -> Complex<T> {
Complex {
re: &self.re * &rhs.re - &self.im * &rhs.im,
im: &self.re * &rhs.im + &self.im * &rhs.re,
}
}
}
// Ref-Value Multiplication
impl<'a, T: Clone> Mul<Complex<T>> for &'a Complex<T>
where
T: Add<T, Output = T>,
T: Sub<T, Output = T>,
&'a T: for<'b> Add<&'b T, Output = T>,
&'a T: for<'b> Mul<&'b T, Output = T>,
&'a T: for<'b> Sub<&'b T, Output = T>,
{
type Output = Complex<T>;
fn mul(self, rhs: Complex<T>) -> Complex<T> {
let t = &rhs;
self.mul(t)
}
}
在您的版本中,ref-value 实现中的生命周期 'b
由特征的用户选择。由于用户可以使用 'b
的任何生命周期,因此 rhs
需要静态生命周期才能使您的代码有效。相反,您想要的是 *'a T
满足 any 给定生命周期 'b
的给定特征界限,这正是 HRTB 的用途。
为第二个实现编写特征边界的另一种重复性较低的方法是:
impl<'a, T: Clone> Mul<Complex<T>> for &'a Complex<T>
where
Self: for<'b> Mul<&'b Complex<T>, Output = Complex<T>>,
{
type Output = Complex<T>;
fn mul(self, rhs: Complex<T>) -> Complex<T> {
self.mul(&rhs)
}
}
内置数字类型使用 macro 实现这些排列。手工完成,我将从你乘以两个值而不是任何引用的情况开始,并确保你的 Complex
结构是 Copy
:
impl<T: Copy> Mul<Complex<T>> for Complex<T>
where
T: Add<T, Output = T>,
T: Sub<T, Output = T>,
T: Mul<T, Output = T>,
{
type Output = Complex<T>;
fn mul(self, rhs: Complex<T>) -> Complex<T> {
unimplemented!()
}
}
请注意,您不需要对 &T
进行任何限制 - 您无论如何都不能 return 引用 T
,因此您将不得不复制它们,这这就是我指定 T: Copy
.
的原因
其余的实现现在很简单,可以委托给最简单的情况:
impl<'a, T: Copy> Mul<Complex<T>> for &'a Complex<T>
where
T: Add<T, Output = T>,
T: Sub<T, Output = T>,
T: Mul<T, Output = T>,
{
type Output = Complex<T>;
fn mul(self, rhs: Complex<T>) -> Complex<T> {
(*self).mul(rhs)
}
}
impl<'a, T: Copy> Mul<&'a Complex<T>> for Complex<T>
where
T: Add<T, Output = T>,
T: Sub<T, Output = T>,
T: Mul<T, Output = T>,
{
type Output = Complex<T>;
fn mul(self, rhs: &'a Complex<T>) -> Complex<T> {
self.mul(*rhs)
}
}
impl<'a, 'b, T: Copy> Mul<&'a Complex<T>> for &'b Complex<T>
where
T: Add<T, Output = T>,
T: Sub<T, Output = T>,
T: Mul<T, Output = T>,
{
type Output = Complex<T>;
fn mul(self, rhs: &'a Complex<T>) -> Complex<T> {
(*self).mul(*rhs)
}
}
我正在处理一个简单的复数示例,并尝试按如下方式实现 ref-value/value-ref 操作:
use std::ops::*;
#[derive(Clone, PartialEq)]
pub struct Complex<T: Sized + Clone> {
pub re: T,
pub im: T,
}
// Ref-Ref Multiplication
impl<'a, 'b, T: Sized + Clone> Mul<&'b Complex<T>> for &'a Complex<T>
where
T: Add<T, Output = T>,
T: Sub<T, Output = T>,
&'a T: Add<&'b T, Output = T>,
&'a T: Mul<&'b T, Output = T>,
&'a T: Sub<&'b T, Output = T>,
{
type Output = Complex<T>;
fn mul(self, rhs: &'b Complex<T>) -> Complex<T> {
panic!("// Details irrelevant")
}
}
// Ref-Value Multiplication
impl<'a, 'b, T: Sized + Clone> Mul<Complex<T>> for &'a Complex<T>
where
T: 'static,
T: Add<T, Output = T>,
T: Sub<T, Output = T>,
&'a T: Add<&'b T, Output = T>,
&'a T: Mul<&'b T, Output = T>,
&'a T: Sub<&'b T, Output = T>,
{
type Output = Complex<T>;
fn mul(self, rhs: Complex<T>) -> Complex<T> {
let t = &rhs;
self.mul(t)
}
}
ref-ref 实现有效,据我了解,它接受两个不同生命周期的引用,returns 一个复杂的值类型。参考值部分是我遇到问题的地方;当我编译时,错误是 rhs
的寿命不够长。我相信我已经知道为什么会这样了,那就是 T 可以在返回值时持有对 rhs 的引用(直接或间接),因此 rhs
超出范围,但 T
可以仍然保留对它的引用。
我的问题是如何传达 T
不会以某种形式或形式引用 rhs
。
关于我迄今为止尝试过或看过的事情的一些注释:
- 更改了任一 Mul 实现的生命周期规范。
- 尝试了生命周期继承,但这指定了
T
持有的引用将至少与T
一样长,所以我想我需要在 [=34= 行中添加更多内容] - 查看了其他实现;要么没有实现案例,要么只是使用克隆来绕过问题。
正如 Peter Hall 在评论中所建议的那样,最简单的解决方案是为您的复杂类型派生 Copy
,并实现值的操作。对于 ref-ref 实现和 ref-val 实现,您可以简单地取消引用引用并使用 val-val 实现。
如果你想让你开始的方法起作用,你需要更高等级的特征边界:
use std::ops::*;
#[derive(Clone, PartialEq)]
pub struct Complex<T: Clone> {
pub re: T,
pub im: T,
}
// Ref-Ref Multiplication
impl<'a, 'b, T: Clone> Mul<&'b Complex<T>> for &'a Complex<T>
where
T: Add<T, Output = T>,
T: Sub<T, Output = T>,
&'a T: Add<&'b T, Output = T>,
&'a T: Mul<&'b T, Output = T>,
&'a T: Sub<&'b T, Output = T>,
{
type Output = Complex<T>;
fn mul(self, rhs: &'b Complex<T>) -> Complex<T> {
Complex {
re: &self.re * &rhs.re - &self.im * &rhs.im,
im: &self.re * &rhs.im + &self.im * &rhs.re,
}
}
}
// Ref-Value Multiplication
impl<'a, T: Clone> Mul<Complex<T>> for &'a Complex<T>
where
T: Add<T, Output = T>,
T: Sub<T, Output = T>,
&'a T: for<'b> Add<&'b T, Output = T>,
&'a T: for<'b> Mul<&'b T, Output = T>,
&'a T: for<'b> Sub<&'b T, Output = T>,
{
type Output = Complex<T>;
fn mul(self, rhs: Complex<T>) -> Complex<T> {
let t = &rhs;
self.mul(t)
}
}
在您的版本中,ref-value 实现中的生命周期 'b
由特征的用户选择。由于用户可以使用 'b
的任何生命周期,因此 rhs
需要静态生命周期才能使您的代码有效。相反,您想要的是 *'a T
满足 any 给定生命周期 'b
的给定特征界限,这正是 HRTB 的用途。
为第二个实现编写特征边界的另一种重复性较低的方法是:
impl<'a, T: Clone> Mul<Complex<T>> for &'a Complex<T>
where
Self: for<'b> Mul<&'b Complex<T>, Output = Complex<T>>,
{
type Output = Complex<T>;
fn mul(self, rhs: Complex<T>) -> Complex<T> {
self.mul(&rhs)
}
}
内置数字类型使用 macro 实现这些排列。手工完成,我将从你乘以两个值而不是任何引用的情况开始,并确保你的 Complex
结构是 Copy
:
impl<T: Copy> Mul<Complex<T>> for Complex<T>
where
T: Add<T, Output = T>,
T: Sub<T, Output = T>,
T: Mul<T, Output = T>,
{
type Output = Complex<T>;
fn mul(self, rhs: Complex<T>) -> Complex<T> {
unimplemented!()
}
}
请注意,您不需要对 &T
进行任何限制 - 您无论如何都不能 return 引用 T
,因此您将不得不复制它们,这这就是我指定 T: Copy
.
其余的实现现在很简单,可以委托给最简单的情况:
impl<'a, T: Copy> Mul<Complex<T>> for &'a Complex<T>
where
T: Add<T, Output = T>,
T: Sub<T, Output = T>,
T: Mul<T, Output = T>,
{
type Output = Complex<T>;
fn mul(self, rhs: Complex<T>) -> Complex<T> {
(*self).mul(rhs)
}
}
impl<'a, T: Copy> Mul<&'a Complex<T>> for Complex<T>
where
T: Add<T, Output = T>,
T: Sub<T, Output = T>,
T: Mul<T, Output = T>,
{
type Output = Complex<T>;
fn mul(self, rhs: &'a Complex<T>) -> Complex<T> {
self.mul(*rhs)
}
}
impl<'a, 'b, T: Copy> Mul<&'a Complex<T>> for &'b Complex<T>
where
T: Add<T, Output = T>,
T: Sub<T, Output = T>,
T: Mul<T, Output = T>,
{
type Output = Complex<T>;
fn mul(self, rhs: &'a Complex<T>) -> Complex<T> {
(*self).mul(*rhs)
}
}