为什么使用“Self”作为参数类型会引发生命周期错误?

Ces*_*ata 8 type-inference lifetime rust

我目前正在关注https://raytracing.github.io/books/RayTracingInOneWeekend.html,但我正在 Rust 中实现所有内容。这是我的向量实现的摘录:

type Scalar = f64;

#[derive(Debug, Default, Clone)]
pub struct Vector {
    x: Scalar,
    y: Scalar,
    z: Scalar,
}

impl Vector {
    fn new(x: Scalar, y: Scalar, z: Scalar) -> Self {
        Self { x, y, z }
    }

    fn x(&self) -> Scalar {
        self.x
    }

    fn y(&self) -> Scalar {
        self.y
    }

    fn z(&self) -> Scalar {
        self.z
    }
}

impl std::ops::Mul<&Vector> for &Vector {
    type Output = Scalar;

    fn mul(self, rhs: Self) -> Self::Output {
        self.x() * rhs.x() + self.y() * rhs.y() + self.z() * rhs.z()
    }
}
Run Code Online (Sandbox Code Playgroud)

当我尝试编译它时,我收到以下消息:

error[E0308]: method not compatible with trait
  --> src/point.rs:33:5
   |
33 |     fn mul(self, rhs: Self) -> Self::Output {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
   |
   = note: expected fn pointer `fn(&point::Vector, &point::Vector) -> _`
              found fn pointer `fn(&point::Vector, &point::Vector) -> _`
note: the lifetime `'_` as defined on the impl at 30:20...
  --> src/point.rs:30:20
   |
30 | impl std::ops::Mul<&Vector> for &Vector {
   |                    ^
note: ...does not necessarily outlive the lifetime `'_` as defined on the impl at 30:20
  --> src/point.rs:30:20
   |
30 | impl std::ops::Mul<&Vector> for &Vector {
   |                    ^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
error: could not compile `raytracing`.
Run Code Online (Sandbox Code Playgroud)

但是,如果我将Self函数上的参数更改mul&Vector,它编译就好了:

error[E0308]: method not compatible with trait
  --> src/point.rs:33:5
   |
33 |     fn mul(self, rhs: Self) -> Self::Output {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
   |
   = note: expected fn pointer `fn(&point::Vector, &point::Vector) -> _`
              found fn pointer `fn(&point::Vector, &point::Vector) -> _`
note: the lifetime `'_` as defined on the impl at 30:20...
  --> src/point.rs:30:20
   |
30 | impl std::ops::Mul<&Vector> for &Vector {
   |                    ^
note: ...does not necessarily outlive the lifetime `'_` as defined on the impl at 30:20
  --> src/point.rs:30:20
   |
30 | impl std::ops::Mul<&Vector> for &Vector {
   |                    ^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
error: could not compile `raytracing`.
Run Code Online (Sandbox Code Playgroud)

这只是生命周期推断失败的情况吗?如果是这样,为什么它会失败,因为编译器似乎已正确推断出所有内容?

Sta*_*eur 5

这是因为生命周期省略规则,错误消息告诉它:

注意:生命周期'_定义在 impl 在 30:20 ...

线路:

impl std::ops::Mul<&Vector> for &Vector {
Run Code Online (Sandbox Code Playgroud)

被解释为:

impl<'a, 'b> std::ops::Mul<&'a Vector> for &'b Vector // Self is &'b Vector
Run Code Online (Sandbox Code Playgroud)

所以终生不匹配是因为:

fn mul(self, rhs: Self) -> Self::Output {
Run Code Online (Sandbox Code Playgroud)

fn mul(self, rhs: &'b Vector) -> Self::Output {
Run Code Online (Sandbox Code Playgroud)

&'a Vector!=&'b Vector所以它无法编译。原因rhs应该是&'a Vector

当您使用Self

impl std::ops::Mul<Self> for &Vector {
Run Code Online (Sandbox Code Playgroud)

变得:

impl<'a> std::ops::Mul<&'a Vector> for &'a Vector {
Run Code Online (Sandbox Code Playgroud)

所以 infn mul(self, rhs: Self) -> Self::Output { rhs会有正确的生命周期<'a>

如果出现生命周期问题,请尝试明确检查编译器是否出错。

最终代码不应包含任何Self关键字以允许不同的生命周期:

impl std::ops::Mul<&Vector> for &Vector {
    type Output = Scalar;

    fn mul(self, rhs: &Vector) -> Self::Output {
        self.x() * rhs.x() + self.y() * rhs.y() + self.z() * rhs.z()
    }
}
Run Code Online (Sandbox Code Playgroud)

明确的:

impl<'a, 'b> std::ops::Mul<&'a Vector> for &'b Vector {
    type Output = Scalar;

    fn mul(self, rhs: &'a Vector) -> Self::Output {
        self.x() * rhs.x() + self.y() * rhs.y() + self.z() * rhs.z()
    }
}
Run Code Online (Sandbox Code Playgroud)