强制/强制评估封闭签名

时间:2016-11-10 19:29:46

标签: rust

这是我想要做的一个人为的例子:

use std::boxed::Box;

#[derive(Debug)]
pub struct Foo<'a>(pub &'a str);

pub trait IntoBox {
    fn into_box<'a>(self) -> Box<Fn(Foo) -> String>;
}

impl<B> IntoBox for B where B: Fn(Foo) -> String + 'static {
    fn into_box(self) -> Box<Fn(Foo) -> String> { Box::new(self) }
}

fn direct_into_box<B: Fn(Foo) -> String + 'static>(b: B) -> Box<Fn(Foo) -> String> {
    Box::new(b)
}

fn main() {
    // Doesn't work
    let x = IntoBox::into_box(|i| format!("{:?}", i) );

    // Works
    let y = IntoBox::into_box(|i: Foo| format!("{:?}", i) );

    // Also works
    let z = direct_into_box(|i| format!("{:?}", i) );
}

如何让我的特质impl与我的direct_into_box进行相同的闭包评估?我本来期望direct_into_box和我的特质impl以同样的方式行事。

x上的错误:

error[E0271]: type mismatch resolving `for<'r> <[closure@<anon>:20:31: 20:53] as std::ops::FnOnce<(Foo<'r>,)>>::Output == std::string::String`
  --> <anon>:20:13
   |
20 |     let x = IntoBox::into_box(|i| format!("{:?}", i) );
   |             ^^^^^^^^^^^^^^^^^ expected bound lifetime parameter , found concrete lifetime
   |
   = note: concrete lifetime that was found is lifetime '_#29r
   = note: required because of the requirements on the impl of `IntoBox` for `[closure@<anon>:20:31: 20:53]`
   = note: required by `IntoBox::into_box`

error[E0281]: type mismatch: the type `[closure@<anon>:20:31: 20:53]` implements the trait `std::ops::Fn<(_,)>`, but the trait `for<'r> std::ops::Fn<(Foo<'r>,)>` is required (expected concrete lifetime, found bound lifetime parameter )
  --> <anon>:20:13
   |
20 |     let x = IntoBox::into_box(|i| format!("{:?}", i) );
   |             ^^^^^^^^^^^^^^^^^
   |
   = note: required because of the requirements on the impl of `IntoBox` for `[closure@<anon>:20:31: 20:53]`
   = note: required by `IntoBox::into_box`

1 个答案:

答案 0 :(得分:3)

听起来像an inference bug in the compiler。似乎发生的事情是编译器在任何生命周期Fn(Foo<'x>) 'x 而不是Fn(Foo<'a>) ,实现'a {/ 1}} em>关闭。

让我们看看我们是否可以通过手工定义结构来复制错误(这需要一个夜间编译器),这样我们就能更好地理解发生了什么。首先,让我们以正确的方式定义结构:

#![feature(fn_traits)]
#![feature(unboxed_closures)]

// Foo and IntoBox unchanged

struct Func;

impl<'a> FnOnce<(Foo<'a>,)> for Func {
    type Output = String;

    extern "rust-call" fn call_once(self, args: (Foo<'a>,)) -> String {
        self.call(args)
    }
}

impl<'a> FnMut<(Foo<'a>,)> for Func {
    extern "rust-call" fn call_mut(&mut self, args: (Foo<'a>,)) -> String {
        self.call(args)
    }
}

impl<'a> Fn<(Foo<'a>,)> for Func {
    extern "rust-call" fn call(&self, (i,): (Foo<'a>,)) -> String {
        format!("{:?}", i)
    }
}

fn main() {
    let x = IntoBox::into_box(Func);
}

这个Func结构编译得很好,行为与原始闭包一样。

现在,让我们打破它:

impl FnOnce<(Foo<'static>,)> for Func {
    type Output = String;

    extern "rust-call" fn call_once(self, args: (Foo<'static>,)) -> String {
        self.call(args)
    }
}

impl FnMut<(Foo<'static>,)> for Func {
    extern "rust-call" fn call_mut(&mut self, args: (Foo<'static>,)) -> String {
        self.call(args)
    }
}

impl Fn<(Foo<'static>,)> for Func {
    extern "rust-call" fn call(&self, (i,): (Foo<'static>,)) -> String {
        format!("{:?}", i)
    }
}

我在这里所做的是,我已经删除了每个<'a>上的impl,因此这些impls在一生中不再是通用的,而且我&#39;已将Foo<'a>替换为Foo<'static>。这意味着现在,只有在&#34;关闭&#34;的参数为Foo<'static>时才会实现这些特征。

无法使用以下错误进行编译:

error[E0271]: type mismatch resolving `for<'r> <Func as std::ops::FnOnce<(Foo<'r>,)>>::Output == std::string::String`
  --> <anon>:51:13
   |
51 |     let x = IntoBox::into_box(Func);
   |             ^^^^^^^^^^^^^^^^^ expected bound lifetime parameter , found concrete lifetime
   |
   = note: concrete lifetime that was found is the static lifetime
   = note: required because of the requirements on the impl of `IntoBox` for `Func`
   = note: required by `IntoBox::into_box`

error[E0277]: the trait bound `for<'r> Func: std::ops::Fn<(Foo<'r>,)>` is not satisfied
  --> <anon>:51:13
   |
51 |     let x = IntoBox::into_box(Func);
   |             ^^^^^^^^^^^^^^^^^ the trait `for<'r> std::ops::Fn<(Foo<'r>,)>` is not implemented for `Func`
   |
   = help: the following implementations were found:
   = help:   <Func as std::ops::Fn<(Foo<'static>,)>>
   = note: required because of the requirements on the impl of `IntoBox` for `Func`
   = note: required by `IntoBox::into_box`

第一个错误是相同的,但编译器提到静态生命周期,而不是像'_#29r这样的内部名称,因为这是我在这里使用的。我怀疑编译器正在对你的代码中没有编译的闭包进行的操作类似于我的第二组impl,只是代替'static,它是&#39我们在Rust中无法命名的其他具体生命周期。第二个错误是不同的,但意味着几乎相同。