通信类型参数的Rust生存期

时间:2018-11-04 19:31:29

标签: rust lifetime type-parameter

我正在研究一个简单的复数示例,并尝试实现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实现有效,据我了解,它接受两个具有不同生命周期的引用,并返回一个复杂的值类型。 ref-value部分是我遇到问题的地方;当我编译时,错误是rhs的寿命不足。我相信我知道为什么会这样,就是说T可以在返回值时持有对rhs的引用(直接或间接),因此rhs超出范围,但是T可以保持对它的引用。

我的问题是如何传达T不会以某种形状或形式保留对rhs的引用。

关于到目前为止我已经尝试过或研究过的事情的一些注释:

  1. 更改了两个Mul实施的生命周期规范。
  2. 尝试了生命周期继承,但这指定了T持有的引用的生存期至少与T一样长,因此我认为“最多”还需要更多内容。 / li>
  3. 查看了其他实现;要么不执行此案,要么仅使用克隆来绕过此问题。

2 个答案:

答案 0 :(得分:1)

正如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满足任何给定生命周期'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)
    }
}

答案 1 :(得分:0)

内置数字类型使用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不需要任何约束-无论如何您都无法返回对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)
    }
}