I've just started with Rust but can't quite grasp lifetimes so I could resolve following issue by myself:
This test project is about simulating a bit to allow tracing it through various bitwise operations, e.g. let newbit = oldbit1 ^ oldbit2
and looking at newbit
I can tell afterwards it came out of an XOR operation with oldbit1
and oldbit2
as operands.
#[derive(Copy,Clone)]
pub enum TraceOperation {
AND,
OR,
XOR,
NOT,
}
#[derive(Copy,Clone)]
pub struct TraceBit<'a> {
source_a: Option<&'a TraceBit<'a>>,
source_b: Option<&'a TraceBit<'a>>,
source_op: Option<TraceOperation>,
value: bool,
}
This compiles, but I don't fully understand why the lifetime parameters are needed that way. I assume that the compiler cannot expect that the members source_a
and source_b
live as long as the struct itself as this may not hold true, so explicit lifetimes are required.
- is this assumption correct?
Further I don't fully understand why I have to re-specify the lifetime parameter for the reference type, i.e. why I have to write source_a: Option<&'a TraceBit<'a>>
as opposed to source_a: Option<&'a TraceBit>
.
- What is the second lifetime used for? How do I read that line out loud? I have:
"
source_a
is a variable of typeOption
that may haveSome
reference (that is valid at least as long as the struct itself and as long as membersource_b
) to an instance ofTraceBit
"
My final issue is that I cannot make it to work using an overloaded operator:
use std::ops::BitXor;
impl<'a> BitXor for TraceBit<'a> {
type Output = Self;
fn bitxor(self, rhs: Self) -> Self {
let valA: usize = if self.value { 1 } else { 0 };
let valB: usize = if rhs.value { 1 } else { 0 };
let val = if valA ^ valB != 0 { true } else { false };
TraceBit { source_a: Some(&self), source_b: Some(&rhs), source_op: Some(TraceOperation::XOR), value: val }
}
}
This is basically pure guessing based on BitXor documentation. So what I try to do, in a very explicit manner, is to perform an xor operation on the two input variables and create a new TraceBit
as output with the inputs stored in it as reference.
error[E0597]: `self` does not live long enough
--> libbittrace/src/lib.rs:37:30
|
37 | TraceBit { source_a: Some(&self), source_b: Some(&rhs), source_op: Some(TraceOperation::XOR), value: val }
| ^^^^ does not live long enough
38 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 31:1...
--> libbittrace/src/lib.rs:31:1
|
31 | / impl<'a> BitXor for TraceBit<'a> {
32 | | type Output = Self;
33 | | fn bitxor(self, rhs: Self) -> Self {
34 | | let valA: usize = if self.value { 1 } else { 0 };
... |
40 | |
41 | | }
| |_^
error[E0597]: `rhs` does not live long enough
--> libbittrace/src/lib.rs:37:53
|
37 | TraceBit { source_a: Some(&self), source_b: Some(&rhs), source_op: Some(TraceOperation::XOR), value: val }
| ^^^ does not live long enough
38 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 31:1...
--> libbittrace/src/lib.rs:31:1
|
31 | / impl<'a> BitXor for TraceBit<'a> {
32 | | type Output = Self;
33 | | fn bitxor(self, rhs: Self) -> Self {
34 | | let valA: usize = if self.value { 1 } else { 0 };
... |
40 | |
41 | | }
| |_^
error: aborting due to 2 previous errors
- Seems like nothing lives longer than the xor operation itself, but how can I resolve this?
I've tried various workarounds/changes to the code but to no avail and in any way I rather like to understand the issue than guessing a correct solution....