LoginSignup
18
8

More than 5 years have passed since last update.

Rustの構造体メンバーにクロージャを持たせるには

Last updated at Posted at 2018-02-25

この記事は

structにIterator traitを実装をして、そのイテレーションに任意のクロージャをfilterとして用いたかった。
そこで表題のようにstructをインスタンス化する際にクロージャをメンバーとしてアサインしようとしたが、少し詰まったのでその備忘録である。

クロージャの型ってなんだっけ

結論から言うとこの問に答えられなかったのが全て。
最初f: Fn(usize) -> boolとか書いてたの本当に愚かだった。

struct A {
    count: usize,
    exp: Fn(usize) -> bool,
}

impl Iterator for A {
    type Item = usize;
    fn next(&mut self) -> Option<usize> {
        self.count += 1;
        if (self.exp)(self.count) {
            Some(self.count)
        } else {
            None
        }
    }
}

fn main() {
    let a = A {
        count: 0,
        exp: |x| x < 5,
    };

    for c in a.into_iter() {
        println!("{}", c);
    }
}

これは下記のエラーをくらう。


   |
22 |         exp: |x| x < 5,
   |              ^^^^^^^^^ expected trait std::ops::Fn, found closure
   |
   = note: expected type `std::ops::Fn(usize) -> bool + 'static`
              found type `[closure@src/main.rs:22:14: 22:23]`

そのままだが、これはFnがtypeではなくtraitだからである。

Fnとfnの違い

結論から言うとクロージャの型はfn(T) -> Uである。

fnprimitive typeだが、Fntraitである。

f: Fn(usize) -> boolをメンバーとして定義するなら、Fnを満たすtypeを別途定義してから渡す必要があるわけで、|x| x < 5はtypeではなく値である。

結論

今回やりたかったのはf: fn(usize) -> boolだったという話。

struct A {
    count: usize,
    exp: fn(usize) -> bool,
}

impl Iterator for A {
    type Item = usize;
    fn next(&mut self) -> Option<usize> {
        self.count += 1;
        if (self.exp)(self.count) {
            Some(self.count)
        } else {
            None
        }
    }
}


fn main() {
    let a = A {
        count: 0,
        exp: |x| x < 5,
    };

    for c in a.into_iter() {
        println!("{}", c);
    }
}
18
8
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
8