2016-08-22 3 views
2

methoddo_somethingから構造体Aに実装されたクロージャを呼び出します。私はこれについていくつかの記事を読んだが、今は少し失われている。メソッド内でクロージャを呼び出す方法

// A simple structure 
struct A<F> { 
    f: F, 
} 

// Implements new and do_something 
impl<F> A<F> where F: Fn() { 
    fn new(f: F) -> A<F> { 
     A { f: f } 
    } 
    fn do_something(&self) { 
     self.f() // Error is here. 
    } 
} 

fn main() { 
    let a = A::new(|| println!("Test")); 
    a.do_something() 
} 

それは、このエラーが表示されます:ここでは簡略化されたバージョンである

error: no method named f found for type &A<F> in the current scope

私はクロージャjust like thisと呼ばれたと思ったが、私が何かを逃したようです。私は、(本当に理解せずにランダムテスト)self.f.call()self.f()を交換しようとしたが、それは2人の事言う:

  1. error: this function takes 1 parameter but 0 parameters were supplied
  2. error: explicit use of unboxed closure method call is experimental [E0174]

は私が最初のエラーについてはよく分からないが、私はそれがだ場合、私は今、この機能を使用しないだろうと思い実験的。

メソッドでクロージャを呼び出す方法はありますか?

答えて

4

は、括弧内のメンバーの名前をラップ:

fn do_something(&self) { 
    (self.f)() 
} 

私が正しくリコール場合は、根本的な原因は、コードを解析する際の優先順位に関係しています。 self.f()は、fという名前のメソッドを検索し、存在しないため失敗します。 (self.f)()は、それが異なるように解析されるようにします。具体的には、メンバ変数を探します。

2

ここでは2番目のエラーが問題です、ボックス化されていないクロージャは処理する苦痛です。クロージャーはあらゆる種類の奇妙なサイズを持つことができるので、になります。ボックスクロージャー(ポインタの後ろに置きます)。

編集: Shepmasterが指摘したように、これは部分的に間違っています。私はクロージャを扱い、それらを渡すときに役立つかもしれないので、以下の古い答えを拡張します。

(また、callはこの場合に必要な実験、およびないので、のはそのせずにそれをやらせる)

struct A<F> { 
    f: Box<F>, 
} 

今それがBox(ヒープに割り当てられたメモリに保存されていることがありますが、他の使用することができます必要に応じて間接指定のタイプ)を使用する場合は、構造体を適切に初期化する必要があります。

fn new(f: F) -> A<F> { 
    A { 
     f: Box::new(f) 
    } 
} 

最後に、これを呼び出すことができますか?

fn do_something(&self) { 
    self.f() // Rust being silly 
} 

しかし、Rustコンパイラは、まだclosure-fieldの代わりにここでメソッドを呼びたいと思っています。そこで、ボックスを明示的に逆参照します。

fn do_something(&self) { 
    (*self.f)() // Explain our intentions to the confused compiler 
} 

これで動作します。しかしここでは間接指示が必要ですか?私はそう思ったが、そうではないようだ(Shepに感謝する)!あなたは、A構造体が既に一般的なので、任意の単一のFタイプに適したサイズでなければならないことがわかります。したがって、我々は間接を必要としない、と古い定義を使用することができます

struct A<F> { 
    f: F, 
} 

をしかし、今、私たちは、少なくともここで何が起こっているかのヒントを持っている、とdo_something

fn do_something(&self) { 
    (self.f)() // Explicitly access a struct member, then call it 
} 
に減少させることができます

これは、コール構文に関してRustコンパイラの構文上の制限にすぎないようです。

+1

それは私ではありません:/とにかくありがとう! –

+1

奇妙なサイズのクロージャについての主なポイントは正確ですが、コンパイラはクロージャのサイズを知っており、ボクシングを避けることは可能です。 'Box'は' Deref'を実装しています。したがって、 '(self.f)()'はボックス化されているときも同様に機能します。 – Shepmaster

関連する問題