回答編集履歴

4

まとめを追記しました

2021/09/27 14:21

投稿

tatsuya6502
tatsuya6502

スコア2046

test CHANGED
@@ -102,7 +102,7 @@
102
102
 
103
103
 
104
104
 
105
- `func`クロージャーの引数`f`をクロージャー(`impl Fn(u8) -> ()`)ではなくて、関数ポインター(`fn() -> (u8)`)にすることで、トレイトオブジェクトを作らないで済むことを思い出しました。自由変数を捕捉しないクロージャー(いわゆる無名関数)なら、関数ポインターに型強制できるので、そういうクロージャーなら受け付けられます。
105
+ `func`クロージャーの引数`f`をクロージャー(`impl Fn(u8) -> ()`)ではなくて、関数ポインター(`fn(u8) -> ()`)にすることで、トレイトオブジェクトを作らないで済むことを思い出しました。自由変数を捕捉しないクロージャー(いわゆる無名関数)なら、関数ポインターに型強制できるので、そういうクロージャーなら受け付けられます。
106
106
 
107
107
 
108
108
 
@@ -145,3 +145,21 @@
145
145
  }
146
146
 
147
147
  ```
148
+
149
+
150
+
151
+ **まとめ**
152
+
153
+
154
+
155
+ - クロージャーを引数に取るクロージャー(`func`)では、ご質問のコードのように、引数となるクロージャー(`f`)をトレイトオブジェクトにする必要がある。(トレイトオブジェクトは柔軟性がある反面、動的ディスパッチによる性能上のオーバーヘッドがあるため、Rustでは一般的に避けられる傾向がある)
156
+
157
+ - 柔軟性を多少犠牲にできるなら、以下のどちらかの方法で動的ディスパッチを避けることができる
158
+
159
+ - `func`側をジェネリックなローカル関数にする。(`f`の型を`impl Fn(u8)`にする) その場合、`func`は(クロージャーではないので)自由変数を捕捉できなくなる
160
+
161
+ - `f`の型を関数ポインター(`fn(u8)`)にする。その場合、`f`は(クロージャーではないので)自由変数を捕捉できなくなる
162
+
163
+
164
+
165
+ まず最後の2つのどちらかにできないかを検討し、無理なら最初の方法(トレイトオブジェクトによる動的ディスパッチ)にするのがいいかもしれません。なお文法上は、最後の関数ポインターを使う方法が、ご質問にある「こう書きたいコード」に一番近くなります。

3

クロージャーの引数に関数ポインターをとる方法について追記しました

2021/09/27 14:21

投稿

tatsuya6502
tatsuya6502

スコア2046

test CHANGED
@@ -95,3 +95,53 @@
95
95
 
96
96
 
97
97
  用途によってはこれらも使えるかもしれません。
98
+
99
+
100
+
101
+ **追記**
102
+
103
+
104
+
105
+ `func`クロージャーの引数`f`をクロージャー(`impl Fn(u8) -> ()`)ではなくて、関数ポインター(`fn() -> (u8)`)にすることで、トレイトオブジェクトを作らないで済むことを思い出しました。自由変数を捕捉しないクロージャー(いわゆる無名関数)なら、関数ポインターに型強制できるので、そういうクロージャーなら受け付けられます。
106
+
107
+
108
+
109
+ ```rust
110
+
111
+ fn outer_func() {
112
+
113
+ // funcクロージャーは引数に関数ポインターをとる
114
+
115
+ let func = |f: fn(u8)| {
116
+
117
+ f(0);
118
+
119
+ };
120
+
121
+
122
+
123
+ // このクロージャーは自由変数を捕捉していないので
124
+
125
+ // 関数ポインターへ型強制できる
126
+
127
+ func(|_i| {});
128
+
129
+
130
+
131
+ // このクロージャーは自由変数(j)を捕捉しているので
132
+
133
+ // 関数ポインターへは型強制できない
134
+
135
+ let j = 10;
136
+
137
+ func(|i| i + j); // error[E0308]: mismatched types
138
+
139
+ // ^^^^^^^^^ expected fn pointer, found closure
140
+
141
+ // note: expected fn pointer `fn(u8)`
142
+
143
+ // found closure `[closure@src/main.rs:15:10: 15:19]`
144
+
145
+ }
146
+
147
+ ```

2

引用箇所が少し言葉足らずだったので、引用範囲を広げました

2021/09/27 13:37

投稿

tatsuya6502
tatsuya6502

スコア2046

test CHANGED
@@ -20,7 +20,7 @@
20
20
 
21
21
 
22
22
 
23
- > その関数内でしか使わない処理をいくつか書くとき、匿名関数を使って実装するという手法を良く使っていて、
23
+ > 同じようで少しづつ違うけれどその関数内でしか使わない処理をいくつか書くとき、匿名関数を使って実装するという手法を良く使っていて、
24
24
 
25
25
 
26
26
 

1

誤字を修正しました

2021/09/27 06:17

投稿

tatsuya6502
tatsuya6502

スコア2046

test CHANGED
@@ -32,7 +32,7 @@
32
32
 
33
33
  pub fn outer_func() {
34
34
 
35
- この関数はouter_func内だけで使用できる
35
+ この関数はouter_func内だけで使用できる
36
36
 
37
37
  関数なのでジェネリクスにできる(implトレイトを引数に取れる)
38
38