微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何使用通用参数包装函数,这些参数在 Rust 中强制命名生命周期为非“静态生命周期

如何解决如何使用通用参数包装函数,这些参数在 Rust 中强制命名生命周期为非“静态生命周期

我正在处理一个更大的私人项目,并引入了类似函数注册表之类的东西,以便使用钩子。到目前为止效果很好,直到我被迫使用具有命名生命周期的类型在我的情况下它是 rusqlite::Transaction<'c>。因此,所有依赖结构也必须引入命名生命周期,对吗?

最后我遇到了一些编译器生命周期错误,我不知道如何解决

为了缩小问题的范围,我编写了此示例代码。请注意,您不能更改事务结构,因此这只是任何需要命名生命周期参数的结构的示例。

use std::error::Error;

struct Holder<T> {
    item: fn(&T) -> (),}

impl <T> Holder<T> {
    fn new(f: fn(&T) -> ()) -> Holder<T>{
        Holder{item: f}
    }

    fn exe(&self,i: &T){
        let f = self.item;
        f(i);
    }
}

struct Transaction<'c> {
    connection: &'c str,}

impl <'c> Transaction<'c> {
    fn new(c: &'c str) -> Transaction {
        Transaction{connection: c}
    }
}

fn doSomething(t: &Transaction) {
    println!("I have done Something with {}",&t.connection);
}

pub fn main() -> Result<(),Box<dyn Error>> {

    //let f: fn(&Transaction) = |x| doSomething(x);
    let h: Holder<Transaction> = Holder::new(doSomething) ;
    {
        let connection = String::from("c1");
        let tran = Transaction::new(&connection);
        h.exe(&tran);
        h.exe(&tran);
        doSomething(&tran);
        doSomething(&tran);
    }
    {
        let connection = String::from("c2");
        let tran = Transaction::new(&connection);
        h.exe(&tran);
        h.exe(&tran);
        doSomething(&tran);
        doSomething(&tran);
    }

    Ok(())
}

如果我使用 doSomething 那么它可以工作,但是如果我将 doSomething 放在我的通用持有人中,我会遇到这样的终身错误

error[E0597]: `tran` does not live long enough
  --> src\t.rs:39:15
   |
   |               ^^^^^ borrowed value does not live long enough
40 |         h.exe(&tran);
41 |     }
   |     - `tran` dropped here while still borrowed
...
45 |         h.exe(&tran);
   |         - borrow later used here

最后,我可以理解问题出现了,因此交易的生命周期与持有人绑定。但是如何告诉 Rust,这个生命周期是一个函数参数,不必绑定到 Holder-Struct,从而使示例可以安全地工作?

解决方法

经过数小时的尝试,重复,再试一次,我找到了解决方案。

仅用 fn(&T) 替换 T 并从外部为 fn(&Transaction) 放入 Transaction 而不是 T 使我的示例最终起作用。

当然,我必须在 impl 之外手动执行该函数。但这种方法也适用于我更大的项目。

感觉有点难看,因此 Rust 的类型系统在这一点上的行为对我来说是不一致的。

完整代码:

use std::error::Error;

struct Holder<T> {
    item: T,}

impl <T> Holder<T> {
    fn new(f: T) -> Holder<T>{
        Holder{item: f}
    }

    fn get(&self) -> &T {
        &self.item
    }
}


struct Transaction<'c> {
    connection: &'c String,}

impl <'c> Transaction<'c> {
    fn new(c: &'c String) -> Transaction {
        Transaction{connection: c}
    }
}

fn doSomething(t: &Transaction) {
    println!("I have done Something with {}",&t.connection);
}

type RegF = fn(&Transaction) -> ();

pub fn main() -> Result<(),Box<dyn Error>> {

    let h: Holder<RegF> = Holder::new(doSomething);

    {
        let connection = String::from("c1");
        let tran = Transaction::new(&connection);
        let f = h.get();
        f(&tran);
        f(&tran);
        doSomething(&tran);
        doSomething(&tran);
    }
    {
        let connection = String::from("c2");
        let tran = Transaction::new(&connection);
        let f = h.get();
        f(&tran);
        f(&tran);
        doSomething(&tran);
        doSomething(&tran);
    }

    Ok(())
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。