質問するログイン新規登録

回答編集履歴

1

説明を少し追加しました

2020/06/24 01:00

投稿

tatsuya6502
tatsuya6502

スコア2055

answer CHANGED
@@ -25,7 +25,7 @@
25
25
 
26
26
  関連関数`new()`の戻り値型は`Self`(`Worker<F>`)ですので、ジェネリクスの型パラメータ`F`を含んでます。そして`F`の具体的な型は`new()`を呼び出す側で決まります。つまり、`new()`は呼び出し側が求める、どんな`Worker<何かの型>`でも返せなければなりません。
27
27
 
28
- 一方、`|x| func_a(x)`は具体的な型を持ちます。もしこれがコンパイルできたとすると、`new()`の戻り値は`Worker<具体的な一つの型>`になり、`Self`と矛盾してしまいます。
28
+ 一方、`|x| func_a(x)`は具体的な型を持ちます。もしこれがコンパイルできたとすると、`new()`の戻り値は`Worker<具体的な一つの型>`になり、`Self`と矛盾してしまいます。そのため型不一致のエラーE0308になるわけです。
29
29
 
30
30
  解決法としては2つあると思います。
31
31
  1. クロージャを`new()`の外側から与える
@@ -49,6 +49,8 @@
49
49
 
50
50
  ## 2. `Worker.func`を具体的な型にする
51
51
 
52
+ `Worker`構造体の`func`フィールドの型を、ジェネリクスの型パラメータではなく、具体的な型にします。
53
+
52
54
  `|x| func_a(x)`は具体的な型を持ちますが、コンパイラが内部的に作成する匿名型なので、ソースコードで型を指定することはできません。
53
55
 
54
56
  しかし、このクロージャをよく見ると自由変数がありません(外側にある変数を環境にキャプチャしていません) こういうクロージャは普通の関数と同じように扱えますので、関数ポインタ型`fn(&[u8]) -> Vec<u8>`へと型強制できます。
@@ -63,7 +65,7 @@
63
65
  impl Worker {
64
66
  fn new() -> Self {
65
67
  Self {
66
- // 自由変数を持たないクロージャは関数ポインタ型に型強制できる
68
+ // 自由変数を持たないクロージャは関数ポインタ型に型強制できる
67
69
  func: |x| func_a(x),
68
70
  }
69
71
  }