简体   繁体   English

函数引用:预期的约束生命周期参数,找到具体的生命周期[E0271]

[英]Function references: expected bound lifetime parameter , found concrete lifetime [E0271]

There are already a lot of threads on this topic but I fail to see if the discussed problems apply to my specific problem. 关于这个主题已经有很多线程但是我没有看到讨论的问题是否适用于我的具体问题。

I have a structure that stores a name and a callback function. 我有一个存储namecallback函数的结构。 Stripped down to the problem it looks like this: 剥离问题看起来像这样:

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
        }
    }
}

What I want to do is store a callback function associated with a name (and prob. more stuff in the future). 我想要做的是存储一个与名称相关的回调函数(以及将来的更多东西)。

But when I try to use this bit of code like so: 但是当我尝试使用这样的代码时:

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

I get the following error message: 我收到以下错误消息:

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);
                                                        ^~~~~~~~~~~~~~

I tried to inline the closure like this 我试着像这样内联封闭

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

but then I get another error 但后来又出现了另一个错误

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

which I believe I understand why I get. 我相信我理解为什么会这样。

I tried using a generic type parameter for Command before switching to a function reference first to store in my Command structure, but when I wanted to initialize a HashSet of command objects like this: 我尝试使用Command的泛型类型参数,然后首先切换到函数引用以存储在我的Command结构中,但是当我想初始化命令对象的HashSet ,如下所示:

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

the compiler wanted me to specify the generic parameter which I think I cannot do as that would mean I could only store the same closure in all my Command objects. 编译器希望我指定我认为不能做的泛型参数,因为这意味着我只能在所有的Command对象中存储相同的闭包。

So my question would be: How can I achieve what I want and what is the best way to do so (and why)? 所以我的问题是:我怎样才能实现我想要的,最好的方法是什么(以及为什么)?

The easy fix (by ljedrz) is that args: &[&str] is not inferred in this case. 简单的修复(由ljedrz)是args: &[&str]在这种情况下不被推断。 However, it may not be enough to solve your problem. 但是,它可能不足以解决您的问题。

When you use a reference to some trait as a function argument, it is treated as a trait object. 当您使用对某个特征的引用作为函数参数时,它将被视为特征对象。 In this case, the &Fn is a trait object that references the closure on the stack. 在这种情况下, &Fn是一个特征对象,它引用堆栈上的闭包。

An easy analogy of trait objects are objects that implement interfaces in other languages. 特征对象的简单类比是在其他语言中实现接口的对象。

However, lifetimes work a bit differently with the trait objects. 但是,生命周期与特征对象的工作方式略有不同。 You can think of them as "detached" from the usual ownership flow. 您可以将它们视为与通常的所有权流程“分离”。 If we were to annotate the Fn trait object lifetime 'c in your example, we would get the following code: 如果我们要在您的示例中注释Fn trait对象的生命周期'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);
}

In the code above, the lifetime 'c describes a scope in which the callback function will be called. 在上面的代码中,生命周期'c描述了将调用回调函数的范围。

The above code, however, is not very practical. 但是,上述代码不太实用。 It couples the command to the scope in which the closure was created (remember, the trait object references the closure in that scope). 它将命令耦合到创建闭包的范围(请记住,trait对象引用该范围内的闭包)。 So you can't exit from the function in which your Command was created, because that would destroy the closure! 因此,您无法退出创建Command的函数,因为这会破坏闭包!

The likely solution is to store the closure on the heap, in Box<Fn(&[&str])> . 可能的解决方案是在Box<Fn(&[&str])>中将闭包存储在堆上。 The lifetime of a trait object in the box (heap memory) is controlled by the creation and destruction of the box, so it is the broadest possible ( 'static ). 框中的特征对象(堆内存)的生命周期由框的创建和销毁控制,因此它是最广泛的( '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));
}

In the example above, the closure will be moved into the box when the box is created, and will be destroyed together with Command . 在上面的示例中,闭包将在创建框时移动到框中,并将与Command一起销毁。

Have you tried specifying the type of args ? 你试过指定args的类型吗? The following compiles for me: 以下编译对我来说:

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

I don't know why it is not inferred, though. 不过,我不知道为什么不推断。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 预期的约束寿命参数,找到的混凝土寿命[E0271] - Expected bound lifetime parameter, found concrete lifetime [E0271] 预期的约束寿命参数,找到具体的寿命 - Expected bound lifetime parameter, found concrete lifetime 如何解决:预期的混凝土寿命,但找到了约束寿命参数 - How to fix: expected concrete lifetime, but found bound lifetime parameter StreamExt.scan() 方法上的“预期绑定生命周期参数,找到具体生命周期” - “expected bound lifetime parameter, found concrete lifetime” on StreamExt .scan() method 锈蚀寿命误差预期具体寿命但发现约束寿命 - Rust lifetime error expected concrete lifetime but found bound lifetime 预期绑定生命周期参数,在尝试传递选项时找到具体生命周期<fnonce></fnonce> - Expected bound lifetime parameter, found concrete lifetime when trying to pass an Option<FnOnce> 预期的混凝土寿命,在结构中存储fn时找到约束寿命参数 - Expected concrete lifetime, found bound lifetime parameter when storing a fn in a struct 尝试调用泛型函数时出现“预期的绑定生命周期参数”错误 - “expected bound lifetime parameter” error when attempting to call a generic function 无法为结构内具有相同生命周期的多个引用推断生命参数的适当生命周期 [E0495] - cannot infer an appropriate lifetime for lifetime parameter with multiple references with the same lifetime inside a struct [E0495] 从闭包填充集合时,键入不匹配“绑定生命周期参数”与“具体生命周期” - Type mismatch “bound lifetime parameter” vs “concrete lifetime” when filling a collection from a closure
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM