发送到函数的借用值在Rust程序中的生存时间不够长

gijlo24d  于 2023-10-20  发布在  其他
关注(0)|答案(1)|浏览(109)

我尝试通过可变引用向函数发送rusqlite语句,让该函数执行查询并将结果打包到Peekable Iterator中。编译器抱怨我借用的语句的寿命不够长。
如果我删除注解并使用alt,则以下程序可以工作。2代替alt.1

use std::iter::Peekable;

use rusqlite::{
    Error,
    MappedRows,
    Row,
    Statement,
    params,
};

fn get_mapped_rows<'stmt>(get_stmt: &'stmt mut Statement<'stmt>,
)-> Peekable<MappedRows<'stmt, impl FnMut(&Row<'_>) -> Result<i64, Error>>> {
    get_stmt
        .query(params![0, 0])
        .unwrap()
        .mapped(|row| {
            Ok(row.get(0)?)
        })
        .peekable()
}

fn main() {
    let conn = rusqlite::Connection::open("db.sqlite3")
        .unwrap();

    let mut get_stmt = conn
        .prepare("SELECT dbl_time FROM log")
        .unwrap();

    // Alt. 1
    let mut mapped_rows = get_mapped_rows(&mut get_stmt);

    /*
    // Alt. 2
    let mut mapped_rows = get_stmt
        .query(params![0, 0])
        .unwrap()
        .mapped(|row| {
            let nbr: i64 = row.get(0)?;
            Ok(nbr)
        })
        .peekable();
     */

    while let Some(row_result) = mapped_rows.next() {
        match row_result {
            Ok(dbl_time) => { println!("dbl_time:{} is_last:{}",
                                       dbl_time,
                                       mapped_rows.peek().is_none()); },
            _ => panic!("Error!"),
        }
    }
}

我希望get_mapped_rows返回的迭代器在get_stmt之前被删除,因此我不明白借用的get_stmt的生存期如何成为问题。
但是编译器说:

error[E0597]: `get_stmt` does not live long enough
  --> src/main.rs:31:43
   |
26 |     let mut get_stmt = conn
   |         ------------ binding `get_stmt` declared here
...
31 |     let mut mapped_rows = get_mapped_rows(&mut get_stmt);
   |                                           ^^^^^^^^^^^^^ borrowed value does not live long enough
...
53 | }
   | -
   | |
   | `get_stmt` dropped here while still borrowed
   | borrow might be used here, when `get_stmt` is dropped and runs the `Drop` code for type `Statement`

**编辑:**最初我试图将两个不同的语句传入函数:

fn get_rows<'stmt>(
    i: u32,
    get_stmt_0: &'stmt mut Statement<'_>,
    get_stmt_1: &'stmt mut Statement<'_>,
) -> Rows<'stmt> {
    let stmt = if i < 42 {
        get_stmt_0
    } else {
        get_stmt_1
    };

    stmt
        .query(params![0, 0])
        .unwrap()
}

在这里使用&'stmt mut Statement<'_>会导致另一个编译器问题:

error: lifetime may not live long enough
  --> src/main.rs:13:9
   |
9  |     get_stmt_0: &'stmt mut Statement<'_>,
   |     ---------- has type `&mut Statement<'1>`
10 |     get_stmt_1: &'stmt mut Statement<'_>,
   |     ---------- has type `&mut Statement<'2>`
...
13 |         get_stmt_0
   |         ^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
   |
   = note: requirement occurs because of a mutable reference to `Statement<'_>`
   = note: mutable references are invariant over their type parameter
   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

error: lifetime may not live long enough
  --> src/main.rs:15:9
   |
9  |     get_stmt_0: &'stmt mut Statement<'_>,
   |     ---------- has type `&mut Statement<'1>`
10 |     get_stmt_1: &'stmt mut Statement<'_>,
   |     ---------- has type `&mut Statement<'2>`
...
15 |         get_stmt_1
   |         ^^^^^^^^^^ assignment requires that `'2` must outlive `'1`
   |
   = note: requirement occurs because of a mutable reference to `Statement<'_>`
   = note: mutable references are invariant over their type parameter
   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

这里我说输入语句和返回值应该共享相同的生命周期。编译器以某种方式指示它们具有不同的类型(分别为不同的生存期'1'2)。那是什么意思?有什么办法解决吗?

编辑2尝试为输入Statements引入另一个生命周期参数'a。函数现在看起来像:

fn get_rows<'stmt, 'a>(
    i: u32,
    get_stmt_0: &'a mut Statement<'_>,
    get_stmt_1: &'a mut Statement<'_>,
) -> Rows<'stmt> where 'a: 'stmt
{
    let stmt = if i < 42 {
        get_stmt_0
    } else {
        get_stmt_1
    };

    stmt
        .query(params![0, 0])
        .unwrap()
}

根据我的理解,我现在声明(使用where子句)Statements的生存期必须至少与返回的Rows的生存期一样长。但我还是得到了和以前一样的错误:

error: lifetime may not live long enough
  --> src/main.rs:14:9
   |
9  |     get_stmt_0: &'a mut Statement<'_>,
   |     ---------- has type `&mut Statement<'1>`
10 |     get_stmt_1: &'a mut Statement<'_>,
   |     ---------- has type `&mut Statement<'2>`
...
14 |         get_stmt_0
   |         ^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
   |
   = note: requirement occurs because of a mutable reference to `Statement<'_>`
   = note: mutable references are invariant over their type parameter
   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

error: lifetime may not live long enough
  --> src/main.rs:16:9
   |
9  |     get_stmt_0: &'a mut Statement<'_>,
   |     ---------- has type `&mut Statement<'1>`
10 |     get_stmt_1: &'a mut Statement<'_>,
   |     ---------- has type `&mut Statement<'2>`
...
16 |         get_stmt_1
   |         ^^^^^^^^^^ assignment requires that `'2` must outlive `'1`
   |
   = note: requirement occurs because of a mutable reference to `Statement<'_>`
   = note: mutable references are invariant over their type parameter
   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

老实说,我不明白这个问题是与生存期有关,还是与在两个不同的输入引用之间进行选择有关。

gev0vcfq

gev0vcfq1#

编译器抱怨Statement s* 中的生存期不同,而不是引用的生存期不同。您需要一个单独的生存期来向编译器传达它们是相同的,而不是让它通过使用'_来推断不同的生存期。这编译:

use rusqlite::{params, Rows, Statement};

fn get_rows<'a, 'stmt>(
    i: u32,
    get_stmt_0: &'stmt mut Statement<'a>,
    get_stmt_1: &'stmt mut Statement<'a>,
) -> Rows<'stmt> {
    let stmt = if i < 42 {
        get_stmt_0
    } else {
        get_stmt_1
    };

    stmt.query(params![0, 0]).unwrap()
}

相关问题