error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements


#1

Hello

I have a E0495 error when i compile my source code. I don’t understand the reason of the problem. anyone can explain to me?

static URL_POSTGRES: &'static str = "postgres://test:test@127.0.0.1";

pub struct SQLContext {
    pub conn: Connection,
    pub transaction: Option<Transaction<'static>>
}

impl SQLContext {
    pub fn new() -> SQLContext {
        SQLContext { conn: Connection::connect(URL_POSTGRES, TlsMode::None).unwrap(), transaction: None }
    }

    pub fn get_conn(&mut self) -> &Connection {
        &self.conn
    }

    pub fn begin_transaction(&mut self) {
        self.transaction = Some(self.conn.transaction().unwrap());
    }
}

fn main() {

    let mut context = SQLContext::new();
    context.begin_transaction();
}

Compiling TestRust v0.1.0 (file:///data/dev/TestRust)
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
–> src/bin/ced.rs:29:43
|
29 | self.transaction = Some(self.conn.transaction().unwrap());
| ^^^^^^^^^^^
|

Thanks in advanced


#2

The error message should tell you the conflicting requirements.

But in this case it seems likely that the transaction() function returns something with a limited lifetime, but you’re trying to store it in a field with the (longer) static lifetime. I think a transaction contains a reference to a connection, so it looks like you’re creating a self-referential struct. That is not supported in the language.


#3

That’s going to be the core issue. Transaction<'static> is also incorrect because the Transaction refers to the Connection object, which in turn is owned by (and lives for as long) as the SQLContext, which itself isn’t 'static.

My suggestion would be to return the Transaction from begin_transaction, rather than trying to store it in a field, and let caller manage its lifetime.


#4

Ok,

transaction function is like this :
pub fn transaction<'a>(&'a self) -> Result<Transaction<'a>> {
self.transaction_with(&transaction::Config::new())
}

My new code is :

pub struct ConnectionPool {
    pub conn: Connection
}

impl ConnectionPool {
    pub fn new() -> ConnectionPool {
        ConnectionPool { conn: Connection::connect(URL_POSTGRES, TlsMode::None).unwrap() }
    }

    pub fn get_conn(&mut self) -> &Connection {
        &self.conn
    }
}

thread_local! {
    pub static CONN_POOL_PG: RefCell<ConnectionPool> = RefCell::new(ConnectionPool::new());
}

fn main() {
    CONN_POOL_PG.with(|mut pool| {
        let mut pool_mut = pool.borrow_mut();
        let conn: &Connection = pool_mut.get_conn();
        let test:Option<Transaction<'static>> = Some(conn.transaction().unwrap());
    });
}

And the new error is :
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
–> src/bin/ced.rs:33:33
|
33 | let mut pool_mut = pool.borrow_mut();
| ^^^^^^^^^^

Why is it difficult for rust to know the lifetime?


#5

Why is it difficult for rust to know the lifetime?

Rust knows the lifetime. You’re trying to set it to something impossible. Again, the error message should show you this.

As shown by the signature of transaction(), the resulting transaction can only live as long as the Connection it’s derived from:

pub fn transaction<'a>(&'a self) -> Result<Transaction<'a>>
                        ^^                             ^^

You’re however trying to store it in a variable with the static lifetime specified. That is longer than the Connection since it only lives until the end of the closure.


#6

You’re really determined to jam that 'static into the Transaction eh? :slight_smile:

You won’t be able to do that with thread_local because they’re not true statics (ie get dropped when thread exits). As such, the LocalKey::with API intentionally prevents you from holding the reference beyond the closure’s lifetime. In addition, you’re taking a temp borrow via the RefCell, which is also going to prevent holding it beyond the closure.

There’s the lazy_static crate but I don’t know if it’ll work with these postgres types.

But, what are you trying to achieve with the static lifetime?


#7

My project is a library (dll or so) that can be used from another program in order to access to database. It is necessary that this library have a uniq connection and use transaction. So i found the threat_local macro to persist in “static” the connection and the transaction. My choice isn’t the good solution?


#8

By unique connection, do you mean it must use a single connection for all db communication? Can you have multiple transactions against the same connection? Is all the db work hidden from users of your lib? A bit of elaboration on your scenario would help.