简体   繁体   English

传达类型参数的 Rust 生命周期

[英]Communicating Rust Lifetimes for Type Parameters

I'm working on a simple complex number example, and trying to implement ref-value/value-ref operations as follows:我正在研究一个简单的复数示例,并尝试按如下方式实现 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)
    }
}

The ref-ref implementation works, and from what I understand it it takes in two references of differing lifetimes, and returns a complex value-type. ref-ref 实现有效,据我所知,它接受两个不同生命周期的引用,并返回一个复杂的值类型。 The ref-value part is where I'm having an issue;参考值部分是我遇到问题的地方; When I compile, the error is that rhs doesn't live long enough.当我编译时,错误是rhs寿命不够长。 I believe I know why this is already, and that is that T could hold a reference (either direct or indirectly) to rhs when the value is returned, thus rhs goes out of scope, but T could hold a reference to it still.我相信我已经知道为什么会这样了,那就是当返回值时 T 可以持有对 rhs 的引用(直接或间接),因此rhs超出范围,但T仍然可以持有对它的引用。

My question is how to communicate that T will not hold some reference to rhs in some shape or form.我的问题是如何传达T不会以某种形状或形式引用rhs

Some notes on things that I've tried so far or looked at:关于我迄今为止尝试过或看过的事情的一些说明:

  1. Changed the lifetime specification on either Mul implementation.更改了任一 Mul 实现的生命周期规范。
  2. Tried lifetime-inheritence, but this specifieds a reference held by T will live at least as long as T , so I think I need something more in the lines of "at most."尝试了生命周期继承,但这指定了T持有的引用将至少与T一样长,所以我认为我需要更多“至多”之类的东西。
  3. Looked at other implementations;查看了其他实现; Either does not implement the case, or just uses clone to bypass the issue.要么不实现这种情况,要么只是使用克隆来绕过问题。

As suggested by Peter Hall in the comments, the easiest solution is to derive Copy for your complex type, and implement the operations for values.正如 Peter Hall 在评论中所建议的,最简单的解决方案是为您的复杂类型派生Copy ,并实现对值的操作。 For the ref-ref implementations and the ref-val implementations, you can then simply dereference the references and use the val-val implementation.对于 ref-ref 实现和 ref-val 实现,您可以简单地取消引用引用并使用 val-val 实现。

If you want to make the approach you started work, you need higher-rank trait bounds:如果你想让你开始的方法起作用,你需要更高等级的特征边界:

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)
    }
}

In your version, the lifetime 'b in the ref-value implementation is chosen by the user of the trait.在您的版本中,引用值实现中的生命周期'b由特征的用户选择。 Since the user could use any lifetime for 'b , rhs would need static lifetime for your code to be valid.由于用户可以为'b使用任何生命周期,因此rhs需要静态生命周期才能使您的代码有效。 What you want instead is that *'a T satisfies the given trait bounds for any given lifetime 'b , which is exactly what HRTBs are for.相反,您想要的是*'a T满足任何给定生命周期'b的给定特征边界,这正是 HRTB 的用途。

An alternative, less repetitive way of writing the trait bounds for the second implementation is this:为第二个实现编写 trait bound 的另一种不太重复的方法是:

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)
    }
}

The built-in numeric types implement these permutations using a macro .内置数字类型使用实现这些排列。 Doing it by hand, I'd start with the case where you are multiplying two values, rather than any references, and make sure that your Complex struct is Copy :手动完成,我将从您将两个值相乘而不是任何引用的情况开始,并确保您的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!()
    }
}

Note that you don't need any constraints on &T - you can't return references to T anyway, so you are going to have to copy them, which is why I've specified T: Copy .请注意,您不需要对&T任何约束 - 无论如何您都无法返回对T引用,因此您将不得不复制它们,这就是我指定T: Copy

The rest of the implementations are now straightforward and can delegate to the simplest case:其余的实现现在很简单,可以委托给最简单的情况:

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)
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM