Created
January 23, 2020 03:36
-
-
Save AlexCharlton/cae34d194c7cb9f1bf51b7cb07fd0231 to your computer and use it in GitHub Desktop.
Avoiding poisoning a lifetime
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// First attempt to fix | |
// https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b976d7a37c585dbbf484f1d5af20a6ac | |
#[derive(Debug)] | |
pub struct A<'a> { | |
pub b: B<'a>, | |
} | |
#[derive(Debug)] | |
pub struct B<'a> { | |
pub link: Option<&'a B<'a>>, | |
} | |
#[derive(Debug)] | |
pub enum ObjectPointer<'a> { | |
A(&'a mut A<'a>), | |
B(&'a mut B<'a>), | |
} | |
impl<'a, 'b: 'a> A<'a> { | |
pub fn apply(&'b mut self) { // This fixes the compilation error inside `apply` | |
println!("I'm doing it with: {:?}", fetch_mut(self)) | |
} | |
} | |
pub fn fetch_mut<'a>(a: &'a mut A<'a>) -> ObjectPointer<'a> { | |
ObjectPointer::B(&mut a.b) | |
} | |
fn main() { | |
let mut a = A { b: B {link: None }}; | |
a.apply(); | |
println!("{:?}", a) // But now calling apply results in the borrow outliving the call | |
// This is because `impl<'a, 'b: 'a> A<'a> {` the pointer passed to fetch_mut is specified as outliving the object it's pointing to | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Fixed version | |
// https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=44174c9650dc0db17cf625291b829df4 | |
#[derive(Debug)] | |
pub struct A<'a> { | |
pub b: B<'a>, | |
} | |
#[derive(Debug)] | |
pub struct B<'a> { | |
pub link: Option<&'a B<'a>>, | |
} | |
#[derive(Debug)] | |
pub enum ObjectPointer<'a: 'b, 'b> { | |
A(&'b mut A<'a>), // Pointers to objects with lifetimes should not share the same lifetime | |
B(&'b mut B<'a>), | |
} | |
impl<'a> A<'a> { | |
pub fn apply(&mut self) { | |
println!("I'm doing it with: {:?}", fetch_mut(self)) | |
} | |
} | |
pub fn fetch_mut<'a, 'b>(a: &'b mut A<'a>) -> ObjectPointer<'a, 'b> { | |
ObjectPointer::B(&mut a.b) | |
} | |
fn main() { | |
let mut a = A { b: B {link: None }}; | |
a.apply(); | |
println!("{:?}", a) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Original version | |
// https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=68bfa9bc94f0ee8c9fd5b73354245953 | |
#[derive(Debug)] | |
pub struct A<'a> { | |
pub b: B<'a>, | |
} | |
#[derive(Debug)] | |
pub struct B<'a> { | |
pub link: Option<&'a B<'a>>, | |
} | |
#[derive(Debug)] | |
pub enum ObjectPointer<'a> { | |
A(&'a mut A<'a>), | |
B(&'a mut B<'a>), | |
} | |
impl<'a> A<'a> { | |
pub fn apply(&mut self) { | |
println!("I'm doing it with: {:?}", fetch_mut(self)) // Calling `fetch_mut` confuses the compiler | |
} | |
} | |
pub fn fetch_mut<'a>(a: &'a mut A<'a>) -> ObjectPointer<'a> { | |
ObjectPointer::B(&mut a.b) | |
} | |
fn main() { | |
let mut a = A { b: B {link: None }}; | |
a.apply(); | |
println!("{:?}", a) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment