Hello Rustaceans ,
Let's say I have a type called Locker
with the following definition:
struct Marker;
struct Locker<'auto> {
marker : Marker,
autoref : Option<&'auto Marker>,
}
and the following methods:
impl<'auto> Locker<'auto> {
pub fn new() -> Self {
Self { marker : Marker, autoref : None }
}
pub fn lock(&'auto mut self) {
self.autoref = Some(&self.marker);
}
}
If I use this struct directly, I can call Locker::lock
and it will compile:
fn main() {
let mut locker : Locker::new();
locker.lock()
}
I can even put this struct in another struct:
fn main() {
struct A<'auto> {
locker: Locker<'auto>,
}
impl<'auto> A<'auto> {
fn borrow_mut(&mut self) -> &mut Locker<'auto> {
&mut self.locker
}
}
let mut locker = A { locker : Locker::new() };
let locker_borrow = locker.borrow_mut();
locker_borrow.lock();
}
But if I put that struct in a RefCell
, then I cannot get the following to compile:
fn main() {
use std::cell::RefCell;
let locker = RefCell::new(Locker::new());
let mut locker_borrow = locker.borrow_mut();
locker_borrow.lock();
}
Compiling playground v0.0.1 (file:///playground)
error[E0597]: `locker_borrow` does not live long enough
--> src/main.rs:22:5
|
22 | locker_borrow.lock();
| ^^^^^^^^^^^^^ borrowed value does not live long enough
23 | }
| - `locker_borrow` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
error: aborting due to previous error
You can try the example on the playground.
My questions are the following:
- Is there a way to modify this example so that it compiles? I'd like to call
Locker::lock
on a aLocker
that lives in aRefCell
. I don't want to change the lifetime of the perma-borrow, though . - Is there a chance that this behavior changes in future versions of Rust, or is it by design? I already tried with the 2018 edition on the playground, which I believe includes NLL. The error message is phrased a little bit differently but I believe it means the same?
Compiling playground v0.0.1 (/playground)
error[E0597]: `locker_borrow` does not live long enough
--> src/main.rs:22:5
|
22 | locker_borrow.lock();
| ^^^^^^^^^^^^^ borrowed value does not live long enough
23 | }
| -
| |
| `locker_borrow` dropped here while still borrowed
| borrow later used here, when `locker_borrow` is dropped
To give a bit of context to my questions, I am working on a reference type that relies on a self-borrow.
If the answer to both my questions is negative, then that means that this type cannot be leaked through a reference cycle by putting it in a Rc
. That would mean that my reference type is safe unless it is put in ManuallyDrop
. Knowing this would allow me to proceed to the next part of my plan .
More generally, I'd find that it would be an interesting property of self-borrowing structs that they statically cannot be put in a cycle (if the method that triggers the self-borrow is called).
Thank you for reading this post !