この記事は
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
である。
fn
はprimitive typeだが、Fn
はtraitである。
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);
}
}