rust で where
の中でトレイト境界を書ける。そして、クロージャはトレイトで実現されている。ってことなんだけど、クロージャを表す型変数のトレイト境界の書き方はなんとも気持ちが悪い。
struct Cacher<T> where T: Fn(u32) -> u32 { calculation: T, value: Option<u32>, }
Closures: Anonymous Functions that Can Capture Their Environment - The Rust Programming Language
トレイト境界と言えば T: Display + Clone
とか、ジェネリックであれば <>
を使って T: AsRef<str>
みたいな記法になるはずだが、 ()
とか ->
とはなんなのか。
答えから言うと、これは Fn
ファミリー独自の記法のようだ。文法的にはこうなっている。 ->
と ()
を使う規則は TypePathFn
と命名されている。
TypePathFn : ( TypePathFnInputs? ) (-> Type)? TypePathFnInputs : Type (, Type)* ,?
これは Foo<(...), Output=B>
の糖衣だとする文章も残っている。
rust-rfcs/0587-fn-return-should-be-an-associated-type.md at master · nox/rust-rfcs · GitHub
ここまで来ると、ああ、やっぱりクロージャはトレイトなんだなという思いになってくるが、現行ではこの規則で脱糖してもコンパイルすることはできず、 TypePathFn
の記法を使わねばならない。
error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead (see issue #29625) --> src/main.rs:175:10 | 175 | where F: FnMut<(u8,), Output=bool> | ^^^^^^^^^^^^^^^^^^^^^^^^^