2016-11-10 13 views
4

の評価を強制私がやろうとしています何の不自然な例です:フォース/ここで閉鎖署名

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と私のtrait implが同じように動作することを期待していました。

x上のエラー:

error[E0271]: type mismatch resolving `for<'r> <[[email protected]<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 `[[email protected]<anon>:20:31: 20:53]` 
    = note: required by `IntoBox::into_box` 

error[E0281]: type mismatch: the type `[[email protected]<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 `[[email protected]<anon>:20:31: 20:53]` 
    = note: required by `IntoBox::into_box` 
+0

私は申し訳ありませんが、私はそれを遊び場で実行することはできません。どのようなアウトプットを得ましたか? – Jacob

+0

私は以前も遊び場で問題を抱えていました。私は私の質問にエラー出力を追加しました。 –

+0

あなたはdirect_into_boxでエラーを受け取らないでしょうか? grrr ...知らない。 – Jacob

答えて

3

an inference bug in the compilerのようですね。コンパイラが特定の有効期間'xの代わりにFn(Foo<'a>)の代わりにFn(Foo<'x>)を実装していて、閉鎖時に'aが実装されていると思われます。

構造体を手作業で定義することでエラーを再現できるかどうかを確認してください(夜間コンパイラが必要です)。何が起きているのかをよりよく理解することができます。まずは、構造体に正しい方法を定義してみましょう:

#![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) 
    } 
} 

私はここでやったことは、私は、各impl<'a>を削除したということです、implsが生涯にわたり、もはや一般的なもので、私は」ようにveはFoo<'a>Foo<'static>に置き換えました。これは、クロージャの引数が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のような内部名の、コンパイラは、静的な寿命を言及しています。私は容疑者あなたのコードでコンパイルされていないクロージャでコンパイラが何をしているのかは、'staticの代わりに私の2番目のインプットセットに似ています。 2番目のエラーは異なりますが、ほぼ同じことを意味します。

+0

新しい問題を作成するために印象的な書き込みを追加/使用する必要がありますか? – Shepmaster

+0

確かに、まだこの問題に関する問題がない場合(私は徹底的に検索しなかったので、問題検索ページにリンクしています:P)、それ以外の場合は既存の問題に追加できます。 –

+0

@FrancisGagné、詳細な説明に感謝します!問題検索へのリンクもありがとうございます。私はちょっと見渡しました。私は[推論が閉鎖に失敗したときの理解できないエラーメッセージ](https://github.com/rust-lang/rust/issues/24680)と[閉鎖に推論された寿命が間違っている](https://github.com/rust-lang/rust/issues/26937)ここで私の問題を説明します。編集:実際に後者はまったく同じ問題ではないかもしれませんが、関連しているようです。 –