关闭签名的强制/强制评估 [英] Force/coerce evaluation of closure signature

查看:28
本文介绍了关闭签名的强制/强制评估的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我正在尝试做的一个人为的例子:

Here is a contrived example of what I am trying to do:

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

如何让我的 trait impl 对闭包进行与我的 direct_into_box 所做的相同的评估?我本来希望 direct_into_box 和我的 trait impl 以同样的方式表现.

How do I get my trait impl to do the same evaluation of the closure as is done by my direct_into_box? I would have expected direct_into_box and my trait impl to behave in the same way.

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`

推荐答案

听起来像 an编译器中的推理错误.似乎发生的事情是编译器实现了 Fn(Foo<'x>) 一个特定的生命周期 'x 而不是 Fn(Foo<'a>) 对于你的闭包的任何生命周期'a.

Sounds like an inference bug in the compiler. What seems to happen is that the compiler implements Fn(Foo<'x>) for one specific lifetime 'x instead of Fn(Foo<'a>) for any lifetime 'a on your closure.

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

Let's see if we can replicate the error by defining a struct by hand (this requires a nightly compiler), so we can better understand what's going on. First, let's define the struct the correct way:

#![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 结构可以很好地编译并且表现得和你原来的闭包一样.

This Func struct compiles fine and behaves just like your original closure.

现在,让我们打破它:

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

我在这里所做的是删除了每个 impl 上的 <'a>,这样 impls 在整个生命周期内不再是通用的,并且我已将 Foo<'a> 替换为 Foo<'static>.这意味着现在,仅当闭包"的参数是 Foo<'static> 时才会实现这些特征.

What I've done here is that I've removed the <'a> on each impl, so that the impls are no longer generic over a lifetime, and I've replaced Foo<'a> with Foo<'static>. This means that now, the traits are only implemented when the "closure"'s argument is a Foo<'static>.

编译失败,出现以下错误:

This fails to compile with the following errors:

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,而是其他一些我们无法在 Rust 中命名的具体生命周期.第二个错误不同,但含义几乎相同.

The first error is the same, but instead of an internal name like '_#29r, the compiler mentions the static lifetime, because that's what I used here. I suspect that what the compiler is doing with the closure that doesn't compile in your code is similar to my second set of impls, just that instead of 'static, it's some other concrete lifetime that we can't name in Rust. The second error is different but means pretty much the same thing.

这篇关于关闭签名的强制/强制评估的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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