RefCell and borrow() cause error[E0597]: borrowed value does not live long enough

⚓ rust    📅 2025-05-15    👤 surdeus    👁️ 4      

surdeus

Warning

This post was published 46 days ago. The information described in this article may have changed.

I'm stumped. I was not getting this error until I had to modify data stored in an Rc, so I added RefCell and used borrow(). The code has further details. This is with Rust 1.81 (the version available on OpenBSD 7.6).

The code is:

use sqlx::{Postgres, Transaction};
use std::cell::{Ref, RefCell};
use std::rc::Rc;

//This minimally reproduces the problem, but the actual complete code base with
//this compilation error is at github.com/onemodel/onemodel in the branch "wip",
//in core/src/model/entity.rs around line 540 (https://github.com/onemodel/onemodel/blob/wip/core/src/model/entity.rs). It has many compilation errors that I can better
//fix after resolving this one (and the one around line 747).
//The complete code is in process of being converted from Scala (commented out) to Rust.
//
//I can't use into_inner() here because of the "dyn Database". These errors did not occur before I
//added the call to borrow(), which was necessary due to use of RefCell, inside the Rc, because 
//I added code that needs to write to the db struct's data. 
//
//To build this, one must first run "cargo update url@2.5.4 --precise 2.3.1".
fn main() {
    let pg = PostgreSQLDatabase {};
    let db = Rc::new(RefCell::new(pg));
    let entity = Entity { db, id: 0 };
    let result = entity.add_quantity_attribute2(None);
    println!(".");
    result.unwrap()
}
struct Entity {
    db: Rc<RefCell<dyn Database>>,
    id: i64,
}
impl Entity {
    fn add_quantity_attribute2<'a, 'b>(
        &'a self,
        //The compiler forced me to use this 'b and other generics due to reasons found in the full program
        //if it is not clear enough here.
        transaction: Option<Rc<RefCell<Transaction<'b, Postgres>>>>,
    ) -> Result<(), String>
    where
        'a: 'b,
    {
        let db: Ref<'b, dyn Database> = self.db.borrow();
        let id: i64 = db.create_quantity_attribute(
            transaction.clone(),
            self.id,
        )?;
        Ok(QuantityAttribute::new2(
            self.db.clone(),
            transaction.clone(),
            id,
        ))
    }
}
pub struct QuantityAttribute {}
impl QuantityAttribute {
    fn new2(
        _db: Rc<RefCell<dyn Database>>,
        _transaction: Option<Rc<RefCell<Transaction<Postgres>>>>,
        _id: i64,
    ) {
        ()
    }
}
trait Database {
    fn create_quantity_attribute<'a, 'b>(
        &'a self,
       transaction: Option<Rc<RefCell<Transaction<'b, Postgres>>>>,
        parent_id_in: i64,
    ) -> Result<i64, String>
    where
        'a: 'b;
}
struct PostgreSQLDatabase {}
impl Database for PostgreSQLDatabase {
    fn create_quantity_attribute<'a, 'b>(
        &'a self,
       _transaction: Option<Rc<RefCell<Transaction<'b, Postgres>>>>,
        _parent_id_in: i64,
    ) -> Result<i64, String>
    where
        'a: 'b,
    {
        Ok(0)
    }
}

The full error message is:

error[E0597]: `db` does not live long enough 
  --> src/main.rs:41:23
   |
31 |       fn add_quantity_attribute2<'a, 'b>(                    
   |                                      -- lifetime `'b` defined here
...                                                                                                                                  
40 |           let db: Ref<'b, dyn Database> = self.db.borrow();
   |               -- binding `db` declared here
41 |           let id: i64 = db.create_quantity_attribute(
   |                         -^                                                                                                      
   |                         |                                    
   |  _______________________borrowed value does not live long enough
   | |               
42 | |             transaction.clone(),
43 | |             self.id,   
44 | |         )?;  
   | |_________- argument requires that `db` is borrowed for `'b`
...                                                               
50 |       }
   |       - `db` dropped here while still borrowed

For more information about this error, try `rustc --explain E0597`.
error: could not compile `my_cargo_app` (bin "my_cargo_app") due to 1 previous error

Here is the Cargo.toml required:

[package]
name = "my_cargo_app"
version = "0.1.0"
edition = "2021"

[dependencies]
# sqlx = { version = "0.6.3", features = [ "runtime-tokio-rustls", "postgres", "uuid" ] }
sqlx = { version = "0.6.3", features = [ "runtime-tokio-rustls", "postgres"] }

6 posts - 3 participants

Read full topic

🏷️ rust_feed