特征界限不满足 [英] The trait bound is not satisfied

查看:62
本文介绍了特征界限不满足的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

协程-rs

这是我要调用的函数:

#[inline]
pub fn spawn<F>(f: F) -> Handle
    where F: FnOnce(&mut Coroutine) + Send + 'static
{
    Self::spawn_opts_impl(Box::new(f), Options::default())
}

然后我创建了一个枚举,因为我实际上想将它从一个线程发送到另一个线程,这也是我将函数装箱的原因.我也匹配了特征约束.

I then created an enum because I actually want to send it from one thread to another, which is also why I have boxed the function. I have also matched the trait constraints.

enum Message {
    Task(Box<FnOnce(&mut Coroutine) + Send + 'static>),
}

但是如果我尝试从 Message 中提取函数:

But if I try to extract the function from a Message:

fn main(){
    let m = Message::Task(Box::new(|me| {
    }));
    let c = match m{
        Message::Task(f) => Coroutine::spawn(f)
    };
}

我收到以下错误:

src/main.rs:168:29: 168:45 error: the trait bound `for<'r> Box<for<'r> std::ops::FnOnce(&'r mut coroutine::asymmetric::Coroutine) + Send>: std::ops::FnOnce<(&'r mut coroutine::asymmetric::Coroutine,)>` is not satisfied [E0277]
src/main.rs:168         Message::Task(f) => Coroutine::spawn(f)
                                            ^~~~~~~~~~~~~~~~
src/main.rs:168:29: 168:45 help: run `rustc --explain E0277` to see a detailed explanation
src/main.rs:168:29: 168:45 help: the following implementations were found:
src/main.rs:168:29: 168:45 help:   <Box<std::boxed::FnBox<A, Output=R> + 'a> as std::ops::FnOnce<A>>
src/main.rs:168:29: 168:45 help:   <Box<std::boxed::FnBox<A, Output=R> + Send + 'a> as std::ops::FnOnce<A>>
src/main.rs:168:29: 168:45 note: required by `coroutine::asymmetric::Coroutine::spawn`

我不知道 Rust 在这里想告诉我什么.我认为问题在于 spawn 需要一个非装箱函数,但如果我尝试取消引用装箱函数,我会得到同样的错误.

I have no idea what Rust is trying to tell me here. I assume that the problem is that spawn expects a non boxed function, but I get the same error if I try to deref the boxed function.

请注意,在提出此问题时,coroutine-rs 未构建,我修复了 这个叉.

Note that at the time this question was asked, coroutine-rs doesn't build, and I fixed the errors in this fork.

推荐答案

让我们仔细阅读错误信息:

Let's read the error message carefully:

src/main.rs:168:29: 168:45 error: the trait bound
    `for<'r>
         Box<
             for<'r> std::ops::FnOnce(
                 &'r mut coroutine::asymmetric::Coroutine
             ) + Send
         >:
     std::ops::FnOnce<
         (
             &'r mut coroutine::asymmetric::Coroutine,
         )>` is not satisfied [E0277]

基本上,您试图将 Box 传递给需要实现 FnOnce 的类型的函数.

Basically, you are trying to pass a Box<FnOnce> to a function that expects a type that implements FnOnce.

然而,你不能调用Box中的函数,因为为了调用它,你需要通过值传递self,这意味着您需要取消对 Box 的引用,但这会产生一个未定义大小的类型,该类型不能按值传递(从 Rust 1.9 开始).

However, you cannot call a function that is in a Box<FnOnce>, because in order to call it, you need to pass self by value, which means that you need to dereference the Box, but that yields an unsized type, which cannot be passed by value (as of Rust 1.9).

目前的解决方法是使用不稳定的FnBox trait 而不是 FnOnce.FnBox 自动为所有实现 FnOnce 的类型实现.以下是我们如何使用它:

The current workaround is to use the unstable FnBox trait instead of FnOnce. FnBox is automatically implemented for all types that implement FnOnce. Here's how we can use it:

#![feature(fnbox)]

use std::boxed::FnBox;

enum Message {
    Task(Box<FnBox(&mut Coroutine) + Send + 'static>),
}

fn main() {
    let m = Message::Task(Box::new(|me: &mut Coroutine| {
    }));
    let c = match m {
        Message::Task(f) => Coroutine::spawn(|me| f.call_box((me,)))
    };
}

注意对Command::spawn的调用会收到一个调用FnBox的闭包,因为我们不能直接传递FnBox由于上述原因,Command::spawn.另外,我必须在第一个闭包上显式注释参数类型,否则编译器会抱怨(预期的具体生命周期,找到绑定的生命周期参数,我认为这是编译器中的一个错误).

Note that the call to Command::spawn receives a closure that calls the FnBox, because we can't pass the FnBox directly to Command::spawn for the reasons mentioned above. Also, I had to explicitly annotate the argument type on the first closure, otherwise the compiler complained (expected concrete lifetime, found bound lifetime parameter, which I think is a bug in the compiler).

这篇关于特征界限不满足的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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