Rustのエラー E0107: takes N generic arguments but M were supplied(ジェネリック引数の数の間違い)
E0107 は、<...> の中の型の数が、その型や関数が期待している数と合っていないという意味のエラーです。Result は2つ(Result<T, E>)、HashMap も2つ(HashMap<K, V>)、Option と Vec は1つを求めます。1つ足りなかったり多すぎたりすると、rustc は enum takes 2 generic arguments but 1 generic argument was supplied(列挙型はジェネリック引数を2つ取るのに、1つしか渡されていない)のように言います。先頭には「struct」「enum」「type alias」「function」「method」のどれかが付きます。とても親切なエラーの1つです。rustc が両方の数を教えてくれるので、型を足すか消すだけで直ります。このシリーズのほかのエラーは、Rustのコンパイルエラー解説を見てください。
エラーメッセージ
Section titled “エラーメッセージ”error[E0107]: enum takes 2 generic arguments but 1 generic argument was supplied --> src/main.rs:1:29 |1 | fn parse_age(text: &str) -> Result<u32> { // ❌ `Result` needs two types | ^^^^^^ --- supplied 1 generic argument | | | expected 2 generic arguments |help: add missing generic argument |1 | fn parse_age(text: &str) -> Result<u32, E> { // ❌ `Result` needs two types | +++このエラーが出るのは、次のプログラムです。
fn parse_age(text: &str) -> Result<u32> { // ❌ `Result` needs two types text.trim().parse()}
fn main() { for input in ["42", "forty"] { match parse_age(input) { Ok(age) => println!("age: {}", age), Err(e) => println!("error: {}", e), } }}コメントは「Result には型が2つ必要」という意味です(エラーになる例なので、コードはそのままにしています)。
エラーの意味
Section titled “エラーの意味”rustc は1行目を2回指しています。
Resultの下の^^^^^^:「expected 2 generic arguments」(ジェネリック引数が2つ必要)。Resultは2つの型パラメータを持つ列挙型です。成功したときの値のTと、エラーのEです。u32の下の---:「supplied 1 generic argument」(ジェネリック引数が1つ渡された)。渡したのはTだけです。help:は、仮のEを足しています。これは型をどこに書くかのヒントで、型そのものではありません。Eを本当のエラー型に置き換えます。
ジェネリック引数は、申込用紙の空欄のようなものです。Result の用紙には「うまくいったら:」と「失敗したら:」の2つの欄があります。片方しか書かないと、窓口で返されてしまいます。
Result<u32> と型を1つだけ書いているコードを読んだことがある人は、とくにこのエラーに出会いがちです。そのコードは間違っていたわけではありません。io::Result<T> や anyhow::Result<T> のような型エイリアスを使っていて、それがエラー型を埋めてくれていたのです。プレリュードのふつうの Result には、そんな省略はありません。
Rust がこうする理由
Section titled “Rust がこうする理由”ジェネリックな型は、すべてのパラメータに値が入るまで、完全な型ではありません。E がわからない Result<u32, E> では、値の大きさも、エラーがどんなものかもわからないので、Rust はそれを使うコードをコンパイルできません。関数の本体から足りない型を推測することもできたはずですが、Rust は関数のシグネチャでは、わざと型を推論しません。シグネチャはほかのコードが頼りにする約束なので、省略せずに書く必要があるのです。
デフォルトを持つパラメータもあります。HashMap<K, V, S = RandomState> には、ハッシュ関数のための3つ目のパラメータがあります。だから HashMap について rustc は「at least 2」(少なくとも2つ)と言うのです。デフォルトで埋められるのは後ろのパラメータだけで、型の作者がデフォルトを付けた場所だけです。ジェネリクスとResultを見てください。
直し方1:足りない型を書く
Section titled “直し方1:足りない型を書く”たいていは、これを選びます。足りないパラメータが何であるべきかを調べて、書きます。parse() の場合、数値の解析に失敗したときのエラー型は std::num::ParseIntError です。
use std::num::ParseIntError;
fn parse_age(text: &str) -> Result<u32, ParseIntError> { text.trim().parse()}
fn main() { for input in ["42", "forty"] { match parse_age(input) { Ok(age) => println!("年齢: {}", age), Err(e) => println!("エラー: {}", e), } }}実行結果:
年齢: 42エラー: invalid digit found in string「invalid digit found in string」(文字列に無効な数字がある)は、Rust の標準ライブラリが表示するエラーメッセージなので、英語のままです。どのエラー型かわからないときは、返しているエラーを出した関数のドキュメントを確かめましょう。HashMap<String> も同じ直し方です。HashMap<String, u32> のように、値が何なのかを書きます。HashMapと独自のエラー型を見てください。
直し方2:io::Result のような、型1つの型エイリアスを使う
Section titled “直し方2:io::Result のような、型1つの型エイリアスを使う”ファイル、ネットワーク、標準入力を扱うとき、またはほかの人のコードで Result<T> を見たときは、これを選びます。std::io::Result<T> は Result<T, std::io::Error> の省略形です。モジュールをインポートして io::Result と書きます。
use std::fs;use std::io;
fn read_config(path: &str) -> io::Result<String> { fs::read_to_string(path)}
fn main() { match read_config("missing-config.toml") { Ok(text) => println!("{}", text), Err(e) => println!("設定を読み込めませんでした: {}", e), }}実行結果:
設定を読み込めませんでした: No such file or directory (os error 2)「No such file or directory」(そのようなファイルやディレクトリはない)は OS のメッセージです。anyhow クレートを使うアプリでは、同じように anyhow::Result<T> と書きます。逆の間違いも E0107 です。io::Result<String, io::Error> と書くと type alias takes 1 generic argument but 2 generic arguments were supplied(型エイリアスはジェネリック引数を1つ取るのに、2つ渡されている)になります。エイリアスにはもうエラー型が入っているからです。2つ目を消しましょう。ファイル入出力とanyhowとthiserrorを見てください。
直し方3:関数をジェネリックにするか、型を書く
Section titled “直し方3:関数をジェネリックにするか、型を書く”その型が自分で定義したジェネリックな構造体で、名前だけを書いたときは、これを選びます。rustc は missing generics for struct `Pair` (構造体 Pair のジェネリクスが足りない)と言います。
error[E0107]: missing generics for struct `Pair` --> src/main.rs:6:13 |6 | fn show(p: &Pair) { // ❌ which `K` and `V`? | ^^^^ expected 2 generic arguments |note: struct defined here, with 2 generic parameters: `K`, `V` --> src/main.rs:1:8 |1 | struct Pair<K, V> { | ^^^^ - -help: add missing generic arguments |6 | fn show(p: &Pair<K, V>) { // ❌ which `K` and `V`? | ++++++note: は「構造体はここで定義されていて、ジェネリックパラメータは K と V の2つ」という意味です。エラーになるプログラムはこちらです(コメントは「どの K と V?」という意味です)。
struct Pair<K, V> { key: K, value: V,}
fn show(p: &Pair) { // ❌ which `K` and `V`? println!("{} = {}", p.key, p.value);}
fn main() { show(&Pair { key: "volume", value: 7 }); show(&Pair { key: "theme", value: "dark" });}help: は Pair<K, V> と書いていますが、show の中にはまだ K も V もないので、それも宣言する必要があります。show は2種類の Pair で呼ばれているので、表示に必要な境界を付けて、ジェネリックにしましょう。
use std::fmt::Display;
struct Pair<K, V> { key: K, value: V,}
fn show<K: Display, V: Display>(p: &Pair<K, V>) { println!("{} = {}", p.key, p.value);}
fn main() { show(&Pair { key: "音量", value: 7 }); show(&Pair { key: "テーマ", value: "ダーク" });}実行結果:
音量 = 7テーマ = ダーク関数が1種類しか扱わないなら、代わりに型を書きます。fn show(p: &Pair<&str, u32>) です。impl Pair { ... } も同じで、impl<K, V> Pair<K, V> { ... } と書く必要があります。ジェネリクスを見てください。
直し方4:多すぎる引数を消す
Section titled “直し方4:多すぎる引数を消す”rustc が「but 2 generic arguments were supplied」(なのに2つ渡されている)と言っていて、もっと少なくしてほしいときは、これを選びます。関数呼び出しのターボフィッシュ ::<> でよく起きます。
error[E0107]: function takes 1 generic argument but 2 generic arguments were supplied --> src/main.rs:13:20 |13 | println!("{}", largest::<i32, i32>(&scores)); // ❌ one type too many | ^^^^^^^ ----- help: remove the unnecessary generic argument | | | expected 1 generic argument |note: function defined here, with 1 generic parameter: `T` --> src/main.rs:1:4 | 1 | fn largest<T: PartialOrd + Copy>(items: &[T]) -> T { | ^^^^^^^ -help は「いらないジェネリック引数を消してください」という意味です。エラーになるプログラムはこちらです(コメントは「型が1つ多い」という意味です)。
fn largest<T: PartialOrd + Copy>(items: &[T]) -> T { let mut best = items[0]; for &item in items { if item > best { best = item; } } best}
fn main() { let scores = [72, 95, 88]; println!("{}", largest::<i32, i32>(&scores)); // ❌ one type too many}largest のパラメータは T の1つだけなので、受け取る型も1つです。largest::<i32>(...) と書くか、ターボフィッシュをまるごと省きます。Rust は引数から T がわかるからです。
fn largest<T: PartialOrd + Copy>(items: &[T]) -> T { let mut best = items[0]; for &item in items { if item > best { best = item; } } best}
fn main() { let scores = [72, 95, 88]; println!("{}", largest(&scores)); println!("{}", largest::<f64>(&[1.5, 0.5]));}実行結果:
951.5ここでいちばん役に立つのは note: の行です。定義を見せて、パラメータを並べてくれるので、自分で数を数えられます。
よく出会う場面
Section titled “よく出会う場面”キーだけの HashMap<String>。 rustc は struct takes at least 2 generic arguments but 1 generic argument was supplied(構造体は少なくとも2つのジェネリック引数を取るのに、1つしか渡されていない)と言います。直し方:HashMap<String, u32> と書くか、HashMap::new() と書いて、最初の insert から Rust に両方を推論させます。HashMapを見てください。
型パラメータが2つある自分の構造体に、1つだけ渡した。 let p: Pair<&str> = ... は struct takes 2 generic arguments but 1 generic argument was supplied になります。直し方:Pair<&str, i32> と書くか、Pair<_, _> と書いて Rust に両方を埋めさせます。Option<i32, i32> はその逆で、enum takes 1 generic argument but 2 generic arguments were supplied になります。値を2つ持ちたいなら、タプルを使って Option<(i32, i32)> と書きます。
ライフタイムも数に入る。 構造体 Excerpt<'a> を Excerpt<'a, 'a> と書くと、struct takes 1 lifetime argument but 2 lifetime arguments were supplied(構造体はライフタイム引数を1つ取るのに、2つ渡されている)になります。直し方:定義の中のパラメータ1つにつき、ライフタイムは1つです。ライフタイムを見てください。.into::<String>() のように、ジェネリックでないメソッドに型を渡すと、method takes 0 generic arguments but 1 generic argument was supplied になります。代わりに let s: String = x.into(); と書きましょう(E0283 を見てください)。
1つ意外なことがあります。Vec<i32, i32> は E0107 ではありません。Vec にはメモリアロケータのための、まだ安定していない2つ目のパラメータがあるので、E0658(英語)(allocator_api)とほかのいくつかのエラーになります。直し方は同じで、Vec<i32>、ペアなら Vec<(i32, i32)> です。
関連するエラー
Section titled “関連するエラー”- E0061:ふつうの引数での同じ間違い。N 個の引数を取る関数に、M 個渡した。
- E0106:ライフタイム指定子が足りない。型の中の参照に
'aが必要なとき。 - E0252:2つの
useの行が同じ名前をインポートしている。Resultがfmt::Resultの意味になって、E0107 が続けて出ることがよくあります。 - E0283:型注釈が必要。
.into::<T>()で E0107 が出たときの正しい直し方です。 - E0401:内側の関数が、外側の関数のジェネリックな
Tを使った。 - コンパイルエラーの一覧:エラー解説ページの全リストです。
理解度チェック
Section titled “理解度チェック”理解度チェック
1. fn load() -> Result<String> で E0107 が出ました。ファイルを読む関数なら、どの戻り値の型で直りますか?
2. HashMap について、rustc が at least 2 generic arguments と言うのはなぜですか?
3. fn show(p: &Pair) で `missing generics for struct Pair が出ました。show はいろいろな種類の Pair` で呼ばれます。どう直しますか?
スコア: 0 / 3
さらに詳しく
Section titled “さらに詳しく”- E0107 — Rust error codes index(英語):このエラーの公式の説明です。ジェネリック引数やライフタイム引数が多すぎる例、少なすぎる例が載っています。
- ジェネリックなデータ型 — The Rust Programming Language 日本語版:
Point<T, U>のような構造体、Result<T, E>のような列挙型、メソッドで<T>がどう働くかです。 - Resultで回復可能なエラー — The Rust Programming Language 日本語版:
Result<String, io::Error>を返す関数と、?演算子です。 std::io::Result— standard library docs(英語):パラメータ1つのエイリアスと、多くのコードがio::Result<T>と書く理由です。- Generic parameters — The Rust Reference(英語):
HashMapのハッシュ関数のようなデフォルトの型パラメータも含めた、正確なルールです。