rust - 函数引用 : expected bound lifetime parameter , 找到了具体的生命周期 [E0271]

标签 rust lifetime

关于这个话题已经有很多话题了,但我看不出所讨论的问题是否适用于我的具体问题。

我有一个存储 namecallback 函数的结构。剥离问题看起来像这样:

pub struct Command<'a> {
    name: &'a str,
    callback: &'a Fn(&[&str]) -> ()
}

impl <'a> Command<'a> {
    pub fn new(name: &'a str, callback: &'a Fn(&[&str]) -> ()) -> Command<'a> {
        Command {
            name: name,
            callback: callback
        }
    }
}

我想做的是存储一个与名称相关联的回调函数(以及 future 可能的更多内容)。

但是当我尝试像这样使用这段代码时:

fn main() {
    let play_callback = |args| {
        println!("Playing something.");
        for arg in args {
            println!("{}", arg);
        }
    };
    let play_command = Command::new("play", &play_callback);
}

我收到以下错误消息:

src/main.rs:22:42: 22:56 error: type mismatch resolving `for<'r, 'r> <[closure@src/main.rs:16:22: 21:3] as std::ops::FnOnce<(&'r [&'r str],)>>::Output == ()`:
 expected bound lifetime parameter ,
    found concrete lifetime [E0271]
src/main.rs:22  let play_command = Command::new("play", &play_callback);
                                                        ^~~~~~~~~~~~~~

我试过像这样内联闭包

fn main() {
    let play_command = Command::new("play", &|args| {
        println!("Playing something.");
        for arg in args {
            println!("{}", arg);
        }
    });
}

但是我又遇到了一个错误

src/main.rs:16:47: 21:7 error: borrowed value does not live long enough

我相信我明白我为什么会这样。

我尝试使用 Command 的通用类型参数,然后首先切换到函数引用以存储在我的 Command 结构中,但是当我想初始化一个 像这样的命令对象的 HashSet:

let mut commands: HashSet<Command> = HashSet::new();

编译器要我指定通用参数,我认为我不能这样做,因为那意味着我只能在所有 Command 对象中存储相同的闭包。

所以我的问题是:我怎样才能实现我想要的,什么是最好的方法(以及为什么)?

最佳答案

简单的修复(由 ljedrz)是 args: &[&str]在这种情况下不推断。但是,这可能不足以解决您的问题。

当您使用对某些特征的引用作为函数参数时,它被视为特征对象。在这种情况下,&Fn是一个特征对象,它引用堆栈上的闭包。

特征对象的一个​​简单类比是用其他语言实现接口(interface)的对象。

但是,生命周期对特征对象的作用略有不同。您可以将它们视为与通常的所有权流“分离”的。如果我们要注释 Fn特征对象生命周期 'c在您的示例中,我们将获得以下代码:

pub struct Command<'a> {
    name: &'a str,
    callback: &'a for<'c> Fn(&'c [&'c str]) -> ()
}

impl <'a> Command<'a> {
    pub fn new<'r>(name: &'r str, callback: &'r for<'c> Fn(&'c [&'c str]) -> ()) -> Command<'r> {
        Command {
            name: name,
            callback: callback
        }
    }
}

fn main() {
    let play_callback = |args: &[&str]| {
        println!("Playing something.");
        for arg in args {
            println!("{}", arg);
        }
    };
    let play_command = Command::new("play", &play_callback);
}

在上面的代码中,生命周期'c描述将调用回调函数的范围。

然而,上面的代码不是很实用。它将命令耦合到创建闭包的范围(请记住,特征对象引用该范围内的闭包)。所以你不能退出你的Command所在的函数。被创建了,因为那会破坏闭包!

可能的解决方案是将闭包存储在堆上,在 Box<Fn(&[&str])> 中.盒子(堆内存)中特征对象的生命周期由盒子的创建和销毁控制,因此它是最广泛的可能('static)。

pub struct Command<'a> {
    name: &'a str,
    callback: Box<Fn(&[&str]) -> ()>
}

impl <'a> Command<'a> {
    pub fn new<'r>(name: &'r str, callback: Box<Fn(&[&str]) -> ()>) -> Command<'r> {
        Command {
            name: name,
            callback: callback
        }
    }
}

fn main() {
    let play_callback = |args: &[&str]| {
        println!("Playing something.");
        for arg in args {
            println!("{}", arg);
        }
    };
    let play_command = Command::new("play", Box::new(play_callback));
}

在上面的例子中,闭包会在盒子被创建时被移动到盒子里,并且会和Command一起被销毁。 .

关于rust - 函数引用 : expected bound lifetime parameter , 找到了具体的生命周期 [E0271],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39395813/

相关文章:

c++ - (全局)静态变量会在程序结束时被销毁吗?

rust - 如何返回带有 `&self` 的 future 组合器

file - 如何将我的 Rust 程序拆分为多个文件?

reference - 如何为对结构的引用实现 Add 特性?

asp.net - 具有 autofac、webforms 和 ServiceLocator 的生命周期范围

c++ - 临时对象的全表达边界和生命周期

rust - 获得具有特定字段的向量,形成结构向量的更好方法?

multithreading - 有没有办法检查连接是否已关闭然后完成线程?

rust - 如何重载引用运算符?

rust - 如何将拥有的盒装结构引用给其他拥有的结构