如何通过&str生存期传递给Box <dyn Fn()>

时间:2019-09-06 16:05:43

标签: rust lifetime

我正在尝试做一个简单的电报机器人。对于提供的问题,我必须回答一些答案。

问题是我无法使用问题(字符串)的借用部分将其传递给数据库保存功能。

我已尽可能减少代码:

pub enum Answer {
    DbCommand(Box<dyn Fn()>),
}

pub fn process(question: &str) -> Answer {
    let parts: Vec<&str> = question
        .split(" ")
        .collect();

    let channel = parts.get(1).unwrap();

    Answer::DbCommand(Box::new(|| {
        save_to_db(channel)
    }))
}

pub fn save_to_db(chan: &str) {
    // Saving to db
}

Playground

输出为:

error[E0621]: explicit lifetime required in the type of `question`
  --> src/lib.rs:12:23
   |
5  |   pub fn process(question: &str) -> Answer {
   |                            ---- help: add explicit lifetime `'static` to the type of `question`: `&'static str`
...
12 |       Answer::DbCommand(Box::new(|| {
   |  _______________________^
13 | |         save_to_db(channel)
14 | |     }))
   | |______^ lifetime `'static` required

如果我增加一些函数生存期,则会收到错误E0495。信息不多

2 个答案:

答案 0 :(得分:3)

std::to_string不分配任何内容,它仅遍历初始字符串,并保留对其的引用。您需要拥有该字符串并将其移至闭包中:

split

在这种情况下,您不需要收集任何东西。

如果您真的不想分配字符串,则可以使结构在整个生命周期中都是通用的,但是我认为这会增加不必要的复杂性。

pub enum Answer {
    DbCommand(Box<dyn Fn()>),
}

pub fn process(question: &str) -> Answer {
    let channel = question.split(" ").nth(1).unwrap().to_owned();

    Answer::DbCommand(Box::new(move || save_to_db(&channel)))
}

pub fn save_to_db(chan: &str) {
    // Saving to db
}

这是因为特征对象默认情况下具有隐式pub enum Answer<'a> { DbCommand(Box<dyn Fn() + 'a>), } pub fn process(question: &str) -> Answer { let channel = question.split(" ").nth(1).unwrap(); Answer::DbCommand(Box::new(move || save_to_db(channel))) } pub fn save_to_db(chan: &str) { // Saving to db } 生存期。

答案 1 :(得分:0)

我的最终代码如下:

pub enum Answer<'a> {
    Text(String),
    DbCommand(Box<dyn Fn() -> Result<String, Error> + 'a>),
}

pub fn process(question: &str) -> Answer {
    let mut parts = question
        .split(" ")
        .map(str::trim)
        .filter(|s| !s.is_empty());

    let command = parts.next();

    match command {
        //...
        Some("/subscribe") => {
            match parts.next() {
                Some(channel) => {
                    Answer::DbCommand(Box::new(move || {
                        db::subscribe_to_channel(&channel)
                        //...
                    }))
                },
                None => Answer::Text("Provide channel name".into()),
            }
        },
        _ => Answer::Text("Invalid command.".into()),
    }
}