もちろんできます:
fn fun_test(value: i32, f: &dyn Fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn times2(value: i32) -> i32 {
2 * value
}
fn main() {
fun_test(5, ×2);
}
これはRustであるため、クロージャーの所有権と存続期間を考慮する必要があります。
TL; DR; 基本的に、クロージャには3つのタイプ(呼び出し可能なオブジェクト)があります。
Fn
:キャプチャしたオブジェクトを変更することはできません。
FnMut
:キャプチャしたオブジェクトを変更できます。
FnOnce
:最も制限されています。呼び出されると、それ自体とそのキャプチャを消費するため、一度だけ呼び出すことができます。
クロージャがFn、FnMut、FnOnceを実装するのはいつですか?を参照してください。詳細については
クロージャーのような単純な関数ポインターを使用している場合、キャプチャセットは空であり、Fn
フレーバーがあります。
もっと凝ったことをしたい場合は、ラムダ関数を使用する必要があります。
Rustには、Cの場合と同じように機能する関数への適切なポインターがあります。それらの型は、たとえばfn(i32) -> i32
です。Fn(i32) -> i32
、FnMut(i32) -> i32
およびFnOnce(i32) -> i32
実際に形質です。関数へのポインターは常にこれら3つすべてを実装しますが、Rustにはクロージャーもあり、関数へのポインター(キャプチャセットが空かどうかによって異なります)に変換される場合とされない場合がありますが、これらの特性の一部は実装されます。
したがって、たとえば、上記の例を拡張できます。
fn fun_test_impl(value: i32, f: impl Fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn fun_test_dyn(value: i32, f: &dyn Fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn fun_test_ptr(value: i32, f: fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn times2(value: i32) -> i32 {
2 * value
}
fn main() {
let y = 2;
fun_test_impl(5, times2);
fun_test_impl(5, |x| 2*x);
fun_test_impl(5, |x| y*x);
fun_test_dyn(5, ×2);
fun_test_dyn(5, &|x| 2*x);
fun_test_dyn(5, &|x| y*x);
fun_test_ptr(5, times2);
fun_test_ptr(5, |x| 2*x);
fun_test_ptr(5, |x| y*x);
}