Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing on lifetimes of underlying reference fields?

Tags:

rust

I'm trying to make two structs that operate on an underlying dataset; one providing immutable "read" operations, the other allowing modification. For this to work, I need to be able to use the read functions from within the modifying object - as such I create a temporary new read object within the modifier function with a view onto the underlying data.

Here's some code:

struct Read<'db> {
    x: &'db i32
}

impl<'db> Read<'db> {
    pub fn get(&'db self) -> &'db i32 { self.x }
}

struct Write<'db> {
    x: &'db mut i32
}

impl<'db> Write<'db> {
    fn new(x: &mut i32) -> Write { Write{x: x} }

    fn as_read(&'db self) -> Read<'db> {
        Read{x: self.x}
    }

    pub fn get(&'db self) -> &'db i32 { self.as_read().get() }
}    


fn main() {
    let mut x = 69i32;
    let y = Write::new(&mut x);
    println!("{}", y.get());
}

It doesn't compile - it seems that despite my best efforts, the lifetime of the reference returned from Read::get is bound to the Write::get's scope, rather than the Write's 'db lifetime. How can I make it compile? (And, is what I want to do possible? Is it the simplest/most concise way of doing it?)

like image 548
Wavin Avatar asked Dec 18 '15 11:12

Wavin


1 Answers

The point the compiler is trying to get across is that &'db self actually means self: &'db Write<'db>. This means that you tie the reference AND the type to the same lifetime. What you actually want in your case is self: &'a Write<'db> where 'a lives just for the as_read function. To be able to return a 'db reference from a 'a reference, you need to specify that 'a lives at least as long as 'db by constraining 'a: 'db.

fn as_read<'a: 'db>(self: &'a Write<'db>) -> Read<'db> {
    Read{x: self.x}
}

pub fn get<'a: 'db>(self: &'a Write<'db>) -> &'db i32 { self.as_read().get() }

or more concisely

fn as_read<'a: 'db>(&'a self) -> Read<'db> {
    Read{x: self.x}
}

pub fn get<'a: 'db>(&'a self) -> &'db i32 { self.as_read().get() }

Try it out in the Playground

like image 183
oli_obk Avatar answered Nov 06 '22 13:11

oli_obk