函数参考:预期的约束寿命参数,找到的具体寿命[E0271] [英] Function references: expected bound lifetime parameter , found concrete lifetime [E0271]

查看:83
本文介绍了函数参考:预期的约束寿命参数,找到的具体寿命[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.

我有一个存储namecallback函数的结构.简而言之,它看起来像这样:

I have a structure that stores a name and a callback function. 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);
}

我收到以下错误消息:

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

但是我又遇到另一个错误

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.

在尝试切换到函数引用以首先存储在我的Command结构中之前,我尝试对Command使用通用类型参数,但是当我想初始化命令对象的HashSet时,如下所示:

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:

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

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

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.

所以我的问题是:我如何才能实现自己想要的目标,以及实现这一目标的最佳方法是什么?为什么?

So my question would be: How can I achieve what I want and what is the best way to do so (and why)?

推荐答案

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

The easy fix (by ljedrz) is that args: &[&str] is not inferred in this case. However, it may not be enough to solve your problem.

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

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.

特质对象的简单类比是使用其他语言实现接口的对象.

An easy analogy of trait objects are objects that implement interfaces in other languages.

但是,生命周期与特征对象的工作方式略有不同.您可以将它们视为与通常的所有权流脱节".如果要在您的示例中注释Fn特征对象生存期'c,我们将获得以下代码:

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:

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描述了将在其中调用回调函数的范围.

In the code above, the lifetime 'c describes a scope in which the callback function will be called.

但是,上面的代码不是很实用.它将命令耦合到在其中创建闭包的作用域(请记住,特征对象在该作用域中引用了闭包).因此,您不能退出创建Command的函数,因为那样会破坏闭包!

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). So you can't exit from the function in which your Command was created, because that would destroy the closure!

可能的解决方案是将闭包存储在堆中的Box<Fn(&[&str])>中.特质对象在盒子(堆内存)中的生存期受盒子的创建和破坏的控制,因此,它的作用范围最大('static).

The likely solution is to store the closure on the heap, in 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).

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一起销毁.

In the example above, the closure will be moved into the box when the box is created, and will be destroyed together with Command.

这篇关于函数参考:预期的约束寿命参数,找到的具体寿命[E0271]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆