RustでFnを返す関数の戻り値で静的ディスパッチされるようにしたい (マクロ + Nightly使用)
何がしたいか?
以下のように関数を返す関数みたいなものを作ろうとしたときに、impl Traitを使ってもコンパイルエラーする。 code:rs
// 注:以下はコンパイルエラー
fn myfun(x: i32) -> impl Fn(&str) -> i32 {
match x {
0 => |s: &str| s.len() as i32 * 10,
1 => move |s: &str| s.len() as i32 + x,
_ => |_: &str| 152,
}
}
以下はコンパイルエラーのメッセージ。
https://gyazo.com/54b62d00b35a24aae2884a1aba5ac06e
恐らく、戻り値のFnが異なりサイズも異なるためエラーしてしまうのだと思う。Boxなどで包むと割と簡単に解決できるが、静的ディスパッチしたいので今回はBoxは避けたい。 関数型言語なら関数を返す関数はスムーズに作れることが理想なので、なるべく非直感的なコードを書いたり記述量が増えることは抑えたい。 解決策
https://gh-card.dev/repos/taiki-e/auto_enums.svg https://github.com/taiki-e/auto_enums
発見元記事にはこのマクロの動作の説明などもある。
依存関係は以下だけ。
code:Cargo.toml
...
auto_enums = "0.5"
変更点は以下のコードを上に加えるだけ。
code:rs
use auto_enums::auto_enum;
fn myfun(x: i32) -> impl Fn(&str) -> i32 { // この行より上を加えている
...
以下は、コード全体。
code:rs
use auto_enums::auto_enum;
fn myfun(x: i32) -> impl Fn(&str) -> i32 {
match x {
0 => |s: &str| s.len() as i32 * 10,
1 => move |s: &str| s.len() as i32 + x,
_ => |_: &str| 152,
}
}
fn main() {
println!("{}", myfun(0)("hello"));
println!("{}", myfun(0)("abc"));
println!("{}", myfun(1)("hello"));
println!("{}", myfun(100)("hello"));
}
$ cargo +nightly run
以下のような出力が得られる。
code:出力結果
50
30
6
152