関数ポインタとクロージャー
関数ポインタ
fn do_twice(f: fn(i32) -> i32, arg: i32) -> { f(arg) + f(arg) } // add_one: fn(i32) -> i32 do_twice(add_one, 1);
fn
: 関数ポインタを表す- 関数の引数にわたすことが出来る
- 3つのクロージャートレイト(
Fn
,FnMut
,FnOnece
)を実装している- 関数とクロージャーは相互に渡すことが出来る
- C関数は関数ポインタのみ引数として渡すことが出来る
map
を使った例
例1: クロージャーを渡す
let list_of_numbers = vec![1, 2, 3]; let list_of_strings = list_of_numbers.iter().map(|i| i.to_string()).collect::<Vec<String>>();
例2: 関数に名前をつけて渡す
let list_of_numbers = vec![1, 2, 3]; let list_of_strings = list_of_numbers.iter().map(ToString::to_string()).collect::<Vec<String>>();
ToString
トレイトに実装されたto_string
を使用しているDisplay
トレイトの親トレイト
例3: タプル構造体もしくはenumの生成
enum Status { Value(u32), Stop, } let list_of_statuses: Vec<Status> = (0u32..20).map(Status::Value).collect();
Status::Value
の初期化関数を使用することによってRange<u32>
からVec<Status>
を生成
クロージャーを返す
- クロージャートレイトは
Sized
トレイトではない - 関数ポインタ
fn
キーワードを返り値の型として使用できない
したがってトレイトオブジェクトとしてクロージャーは返せない
fn return_closure() -> dyn Fn(i32) -> i32 { |x| x + 1 }
error[E0746]: return type cannot have an unboxed trait object | 1 | fn returns_closure() -> dyn Fn(i32) -> i32 { | ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> help: use `impl Fn(i32) -> i32` as the return type, as all return paths are of type `[closure@/Users/yossan/testcodes/rust/garbage/クロージャーは返せない.rs:2:5: 2:14]`, which implements `Fn(i32) -> i32` | 1 | fn returns_closure() -> impl Fn(i32) -> i32 { | ^^^^^^^^^^^^^^^^^^^
クロージャーを返す場合は、impl
キワードを使うか、Box
型に格納するか
fn returns_closure() -> impl Fn(i32) -> i32 { |x| x + 1 }
- クロージャーは実行時には具体型に変換される
参照
https://doc.rust-lang.org/book/ch19-05-advanced-functions-and-closures.html