In my library, I have a context type which holds some mutable references its methods use to do stuff (get common data, send messages, etc). Let's call it MyContext
. An example of a function that uses MyContext:
fn example_function(context: &mut MyContext) {
*context.my_ref = 42;
}
struct MyContext<'a> {
my_ref: &'a mut i32,
// ...
}
For various reasons, I have another context type OtherContext
, which holds some of the same mutable references as the first one. I need to create an OtherContext
object from a MyContext
. The OtherContext will never outlive the MyContext.
At first I tried to write it this way:
struct MyContext<'a> {
my_ref: &'a mut i32,
// ...
}
impl<'a> MyContext<'a> {
fn get_other_context(&mut self) -> OtherContext<'a> {
OtherContext {
my_ref: self.my_ref,
}
}
}
struct OtherContext<'a> {
my_ref: &'a mut i32,
}
To which the compiler replies:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/lib.rs:12:9
|
12 | OtherContext {
| ^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> src/lib.rs:11:26
|
11 | fn get_other_context(&mut self) -> OtherContext<'a> {
| ^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:13:21
|
13 | my_ref: self.my_ref,
| ^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
--> src/lib.rs:10:6
|
10 | impl<'a> MyContext<'a> {
| ^^
note: ...so that the types are compatible
--> src/lib.rs:12:9
|
12 | / OtherContext {
13 | | my_ref: self.my_ref,
14 | | }
| |_________^
= note: expected `OtherContext<'a>`
found `OtherContext<'_>`
Ouch.
From what I'm understanding, the compiler thinks I'm borrowing from self
, and, given 's
the lifetime of &mut self
, wants 's: 'a
, in other words, want the lifetime of the context object and the context being pointed to to be the same.
But this is super inconvenient!
While this compiles:
fn get_other_context<'s: 'a>(&'s mut self) -> OtherContext<'a> { ... }
If I try to call it from my example function:
fn example_function(context: &mut MyContext) {
*context.my_ref = 42;
let other_context = context.get_other_context;
}
... then I get the following error:
error[E0623]: lifetime mismatch
--> src/lib.rs:3:33
|
1 | fn example_function(context: &mut MyContext) {
| --------------
| |
| these two types are declared with different lifetimes...
2 | *context.my_ref = 42;
3 | let other_context = context.get_other_context();
| ^^^^^^^^^^^^^^^^^ ...but data from `context` flows into `context` here
In other words, if I want to re-borrow MyContext into a different type of context object, then I need to tell the compiler that the lifetime of MyContext and the lifetime of the data it points to are the same, which reasonably breaks the code I might want to use MyContext in, even though I'm creating temporary references that are dropped when they're no longer used anyway.
Is there a saner way to write get_other_context()
that I'm not seeing? Conceptually speaking, what potential harm in my code is the borrow checker trying to warn me about?