I'm currently following along with https://raytracing.github.io/books/RayTracingInOneWeekend.html but I'm implementing everything in Rust. Here's a excerpt from my vector implementation:
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()
}
}
When I try to compile it, I get the following message:
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`.
However, if I change the Self
parameter on the mul
function to &Vector
, it compiles just fine:
[...]
fn mul(self, rhs: &Vector) -> Self::Output {
[...]
Is this just a case where the lifetime inference fails? If so, why is it failing, since the compiler seems to have inferred everything correctly?
It's because of rule of lifetime elision, the error message tell it:
note: the lifetime
'_
as defined on the impl at 30:20...
The line:
impl std::ops::Mul<&Vector> for &Vector {
is interpreted as:
impl<'a, 'b> std::ops::Mul<&'a Vector> for &'b Vector // Self is &'b Vector
and so lifetime mismatch because:
fn mul(self, rhs: Self) -> Self::Output {
is
fn mul(self, rhs: &'b Vector) -> Self::Output {
&'a Vector
!= &'b Vector
so it's can't compile. Cause rhs
should be &'a Vector
.
When you use Self
:
impl std::ops::Mul<Self> for &Vector {
become:
impl<'a> std::ops::Mul<&'a Vector> for &'a Vector {
so in fn mul(self, rhs: Self) -> Self::Output {
rhs
will have the correct lifetime <'a>
If a lifetime problem occurs try to be explicit to check if compiler get it wrong.
The final code should not contain any Self
keyword to allow different lifetime:
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()
}
}
explicit:
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()
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With