【问题标题】:The trait bound is not satisfied特征界限不满足
【发布时间】:2016-06-12 21:36:40
【问题描述】:

Coroutine-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())
}

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

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

但如果我尝试从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 需要一个非装箱函数,但如果我尝试取消装箱函数,我会得到同样的错误。

请注意,在提出这个问题时,coroutine-rs 没有构建,我修复了 this fork 中的错误。

【问题讨论】:

    标签: rust


    【解决方案1】:

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

    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&lt;FnOnce&gt; 传递给期望实现 FnOnce 的类型的函数。

    但是,您不能调用 Box&lt;FnOnce&gt; 中的函数,因为要调用它,您需要按值传递 self,这意味着您需要取消引用 Box,但这会产生一个无大小的类型,不能按值传递(从 Rust 1.9 开始)。

    当前的解决方法是使用不稳定的FnBox 特征而不是FnOnce。对于实现FnOnce 的所有类型,都会自动实现FnBox。下面是我们如何使用它:

    #![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。另外,我必须在第一个闭包上显式注释参数类型,否则编译器会抱怨(expected concrete lifetime, found bound lifetime parameter,我认为这是编译器中的一个错误)。

    【讨论】:

    • 谢谢。基本上这意味着我将有 2 个函数分配和 2 个函数调用,对吗?是否也可以扩展Coroutine 以便它也可以接受Box&lt;FnOnce&gt; 而不仅仅是FnOnce?然后我就不必绕道 FnBox 了?
    • 是的,会有2个函数分配,但是调用FnBox的闭包是在栈上分配的,所以相对便宜。是的,会有一个额外的函数调用。此外,Coroutine 可能会被改编,尽管您有一个 Box&lt;FnBox + Send&gt;Coroutine 目前处理的是不兼容的 Box&lt;FnBox&gt;
    猜你喜欢
    • 2022-11-27
    • 2021-08-23
    • 2019-05-11
    • 1970-01-01
    • 2021-01-17
    • 2019-10-11
    • 1970-01-01
    • 2021-02-04
    • 2021-03-30
    相关资源
    最近更新 更多