Rustのエラー E0599: no method named X found(メソッドが見つからない)
E0599 は、呼び出したメソッドを、Rust がその型の上で見つけられなかった、という意味のエラーです。とてもよく出会うエラーで、原因はたいてい次のどれかです。インポートしていないトレイト、中身を取り出していない Option、イテレータのつもりで扱った Vec、または単純なつづりの間違い。うれしいことに、rustc の help: の行が、そのまま正しい直し方を教えてくれることがよくあります。このシリーズのほかのエラーは、Rustのコンパイルエラー解説を見てください。
エラーメッセージ
Section titled “エラーメッセージ”error[E0599]: no method named `write_all` found for struct `Stdout` in the current scope --> src/main.rs:5:9 |5 | out.write_all(b"Server started\n").unwrap(); | ^^^^^^^^^ | = note: the method is available for `Stdout` here | = help: items from traits can only be used if the trait is in scopehelp: trait `Write` which provides `write_all` is implemented but not in scope; perhaps you want to import it |1 + use std::io::Write; |1行目は「現在のスコープで、構造体 Stdout に write_all というメソッドが見つからない」という意味です。help は「トレイトのアイテムは、そのトレイトがスコープにあるときだけ使える」「write_all を提供する Write トレイトは実装されているがスコープにない。インポートしてはどうか」と教えてくれています。
このエラーが出るのは、次のプログラムです。
use std::io;
fn main() { let mut out = io::stdout(); out.write_all(b"Server started\n").unwrap();}エラーの意味
Section titled “エラーの意味”^^^^ の印が付いているのはメソッド名の write_all で、1行目には Rust がどの型を調べたかが書かれています。Stdout ですね。つまりこのメッセージは、「Stdout を調べたけれど、ここで使ってよい write_all というメソッドは見つからなかった」と言っています。
この1行目に出てくる型が、いちばん役に立つ手がかりです。思っていた型ではなく Option<T>、Result<T, E>、Vec<_>、あるいは型引数 T と書かれていたら、下のどの直し方が必要か、もうわかったようなものです。
Rust がこうする理由
Section titled “Rust がこうする理由”Rust では、多くのメソッドは型そのものに属しているわけではありません。トレイト(trait)から来ています。write_all は Write トレイトのメソッドで、Stdout はこのトレイトを実装しています。ただし、トレイトのメソッドが使えるのは、そのトレイトがスコープに入っているファイルの中だけです。ふつうは use の行で持ち込みます。「items from traits can only be used if the trait is in scope」は、まさにこのことを言っています。
このルールのおかげで、コードの動きが予測しやすくなります。2つのクレートが、別々のトレイトを通して、同じ型に write_all という名前のメソッドを追加することもできます。もしすべてのトレイトがいつも有効だったら、その呼び出しがどちらを指すのかわかりません。このルールがあるので、数に入るのは自分でインポートしたトレイトだけです。
ほかの原因は、Rust の厳密な型から来ています。Option<&str> は &str ではないので、&str のメソッドは持っていません。ジェネリックな T はどんな型にでもなれるので、Rust は T の境界(bound)が約束しているメソッドしか呼ばせてくれません。
直し方1:トレイトをインポートする
Section titled “直し方1:トレイトをインポートする”help に「items from traits can only be used if the trait is in scope」と出たときは、これを選びます。rustc が提案する use の行を追加しましょう。
use std::io::{self, Write};
fn main() { let mut out = io::stdout(); out.write_all(b"Server started\n").unwrap();}実行結果:
Server started(エラーになる例と比べやすいように、ここでは表示する文字列を英語のままにしています。)
rand クレートでも同じことが起きます。インポートしないと rng.random_range(1..=6) がエラーになり、rustc がどのトレイトを持ち込めばよいか教えてくれます。
help: trait `RngExt` which provides `random_range` is implemented but not in scope; perhaps you want to import it |1 + use rand::RngExt;注意:rand 0.10 では、このトレイトは RngExt です。古いチュートリアルには use rand::Rng と書かれていますが、rand 0.10 でそのインポートを書くと、まったく同じこのエラーが出ます。チュートリアルではなく、help: の行に従いましょう。
直し方2:先に Option や Result から値を取り出す
Section titled “直し方2:先に Option や Result から値を取り出す”エラーに出てくる型が Option<T> や Result<T, E> のときは、これを選びます。ほしい値はその中に入っているので、メソッドを呼ぶ前に取り出す必要があります。
error[E0599]: no method named `to_uppercase` found for enum `Option<T>` in the current scope --> src/main.rs:4:39 |4 | println!("First guest: {}", first.to_uppercase()); | ^^^^^^^^^^^^ method not found in `Option<&&str>`「列挙型 Option<T> に to_uppercase というメソッドが見つからない」「Option<&&str> にはこのメソッドがない」という意味です。first() はリストが空かもしれないので、Option を返します。rustc は .expect(...) を提案しますが、これは None のときにパニックします。ふつうは、両方の場合をきちんと扱うほうがよいでしょう。
fn main() { let guests = vec!["ana", "bo", "chen"];
match guests.first() { Some(name) => println!("First guest: {}", name.to_uppercase()), None => println!("No guests yet"), }
let shout = guests.last().map(|name| name.to_uppercase()); println!("Last guest: {:?}", shout);}実行結果:
First guest: ANALast guest: Some("CHEN").map() は中の値に対して処理を実行し、Option の包みはそのまま残します。Result(たとえば .parse() の結果)なら、match、.unwrap_or(...)、または Result を返す関数の中で ? を使います。詳しくは Option と Result を見てください。
直し方3:Vec に .iter() を呼ぶ
Section titled “直し方3:Vec に .iter() を呼ぶ”Vec に直接 .map() や .filter() などのイテレータのメソッドを呼んだときは、これを選びます。この場合、エラーの形が少し違います。
error[E0599]: the method `map` exists for struct `Vec<{integer}>`, but its trait bounds were not satisfied --> src/main.rs:3:35 |3 | let curved: Vec<i32> = scores.map(|s| s + 5).collect(); | ^^^ | = note: the following trait bounds were not satisfied: `Vec<{integer}>: Iterator`「Vec<{integer}> に map メソッドはあるが、トレイト境界を満たしていない」「Vec<{integer}>: Iterator が満たされていない」という意味です。filter などのメソッドでは、メッセージがもう少し親切です。rustc は Vec<i32> が「is not an iterator」(イテレータではない)と言い、help: call `.into_iter()` first(先に .into_iter() を呼んで)と付け加えます。原因も直し方も同じです。
Vec<{integer}>: Iterator が「満たされていない」のは、Vec がコレクションであって、イテレータではないからです。.iter()(要素を借用する)か .into_iter()(要素を受け取る)で、イテレータを作ってもらいましょう。
fn main() { let scores = vec![70, 85, 92]; let curved: Vec<i32> = scores.iter().map(|s| s + 5).collect(); println!("{:?}", curved);}実行結果:
[75, 90, 97]直し方4:ジェネリックな T にトレイト境界を付ける
Section titled “直し方4:ジェネリックな T にトレイト境界を付ける”エラーに「for type parameter T」(型引数 T に対して)メソッドが見つからない、と出たときは、これを選びます。ジェネリクスの関数の中では、Rust は T の境界が約束していることしか知りません。何も付いていない T は何も約束していないので、メソッドを1つも持っていません。
error[E0599]: no method named `to_string` found for type parameter `T` in the current scope --> src/main.rs:2:26 |1 | fn describe<T>(item: T) -> String { | - method `to_string` not found for this type parameter2 | format!("[{}]", item.to_string()) | ^^^^^^^^^ method cannot be called on `T` due to unsatisfied trait bounds |help: the following trait defines an item `to_string`, perhaps you need to restrict type parameter `T` with it: |1 | fn describe<T: ToString>(item: T) -> String { | ++++++++++help は「to_string を定義しているのは次のトレイトなので、型引数 T をそれで制限する必要があるかもしれない」と提案しています。rustc が提案する境界を付けましょう。これで、文字列に変換できる型だけを受け取るようになります。
fn describe<T: ToString>(item: T) -> String { format!("[{}]", item.to_string())}
fn main() { println!("{}", describe(42)); println!("{}", describe("ready"));}実行結果:
[42][ready]よく出会う場面
Section titled “よく出会う場面”- つづりの間違いや、ほかの言語のメソッド名。
Vecにtasks.push_back(...)と書くとhelp: you might have meant to use `push`(pushのことではありませんか)と出ます。tasks.lenght()ならhelp: there is a method `len` with a similar name(似た名前のメソッドlenがある)です。直し方:rustc が提案する名前を使います。 - 書いていない
Type::new()を呼ぶ。 Rust には、自動で用意されるコンストラクタはありません。Account::new("Ana", 100)はno associated function or constant named `new` found for struct `Account`(構造体Accountにnewという関連関数や定数がない)というエラーになります。直し方:impl Account { fn new(owner: &str, balance: i64) -> Self { ... } }を追加するか、Account { owner: ..., balance: ... }で直接作ります。詳しくは構造体を見てください。 - 関連関数をドットで呼ぶ。
fn new() -> Selfにself引数がないのにacc.new()と書くと、「this is an associated function, not a method」(これはメソッドではなく関連関数です)というエラーになります。直し方:型に対してAccount::new()と呼びます。
関連するエラー
Section titled “関連するエラー”- E0425:このスコープに値が見つからない:型のメソッドではなく、名前そのものが見えない。
- E0277:トレイト境界を満たしていない:関数や演算子が必要とするトレイトを、型が実装していない。ジェネリックなコードでは E0599 と一緒に出ることがよくあります。
- E0308:型の不一致:
Tが必要なところにOption<T>がある、またはその逆。 - E0382:ムーブされた値の使用:
.iter()を.into_iter()に変えたあとによく出ます。 - コンパイルエラーの一覧:エラー解説ページの全リストと、それぞれの短い説明です。
理解度チェック
Section titled “理解度チェック”理解度チェック
1. rustc が「items from traits can only be used if the trait is in scope」と表示しました。どうすればよいですか?
2. names.first().to_uppercase() が Option<&&str> について E0599 になりました。なぜですか?
3. Vec<i32> に scores.filter(...) を呼んだら、rustc が「Vec<i32> is not an iterator」と言いました。直し方はどれですか?
スコア: 0 / 3
さらに詳しく
Section titled “さらに詳しく”- E0599 — Rust error codes index(英語):このエラーの公式の説明です。
- トレイト:共通の振る舞いを定義する — The Rust Programming Language 日本語版:トレイトが型にメソッドを追加するしくみと、トレイト境界の使い方です。
- 一連の要素をイテレータで処理する — The Rust Programming Language 日本語版:
iter()、into_iter()、mapなどのイテレータのメソッドを説明しています。 Option— 標準ライブラリのドキュメント(英語):Optionから値を取り出すためのメソッドが全部載っています。- The Rust prelude — 標準ライブラリのドキュメント(英語):いつでもスコープに入っているトレイトの一覧と、
Writeがそこに含まれていない理由がわかります。