関数をパラメータとして渡すことはできますか? できない場合、代替案として良いものは何ですか?
いくつかの異なる構文を試しましたが、適切なものが見つかりませんでした。次のようにすればいいことはわかっています:
fn example() {
let fun: fn(value: i32) -> i32;
fun = fun_test;
fun(5i32);
}
fn fun_test(value: i32) -> i32 {
println!("{}", value);
value
}
しかし、これは関数を別の関数にパラメータとして渡すものではありません。
fn fun_test(value: i32, (some_function_prototype)) -> i32 {
println!("{}", value);
value
}
ベストアンサー1
できますよ:
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
: 最も制限されています。呼び出されると、それ自体とそのキャプチャが消費されるため、1 回しか呼び出すことができません。
見るクロージャはいつ 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;
//static dispatch
fun_test_impl(5, times2);
fun_test_impl(5, |x| 2*x);
fun_test_impl(5, |x| y*x);
//dynamic dispatch
fun_test_dyn(5, ×2);
fun_test_dyn(5, &|x| 2*x);
fun_test_dyn(5, &|x| y*x);
//C-like pointer to function
fun_test_ptr(5, times2);
fun_test_ptr(5, |x| 2*x); //ok: empty capture set
fun_test_ptr(5, |x| y*x); //error: expected fn pointer, found closure
}