Rust 错误 E0599:no method named X found(找不到方法)
E0599 的意思是:你调用了一个方法,但 Rust 在这个类型上找不到它。这个错误非常常见,原因通常就是那么几种:忘了导入某个 trait、没有先拆开 Option、把 Vec 当成了迭代器,或者只是拼错了。好消息是,rustc 的 help: 行经常会直接告诉你该怎么改。本页是 Rust 编译错误详解系列的一部分。
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; |第一行的意思是“在当前作用域里,结构体 Stdout 上找不到名为 write_all 的方法”。help 说明:trait 里的方法只有在这个 trait 位于作用域内时才能使用;提供 write_all 的 Write trait 已经实现了,只是没有引入,所以建议你导入它。
产生这个错误的程序是这样的:
use std::io;
fn main() { let mut out = io::stdout(); out.write_all(b"Server started\n").unwrap();}这个错误是什么意思
Section titled “这个错误是什么意思”^^^^ 标出的是方法名 write_all,第一行则告诉你 Rust 是在哪个类型上找的:Stdout。所以这条信息说的是:“我在 Stdout 上找过了,没有一个叫 write_all、而且在这里允许你用的方法。”
第一行里的类型是整条信息里最有用的线索。如果它写的是 Option<T>、Result<T, E>、Vec<_>,或者一个类型参数 T,而你以为是别的类型,那你已经知道该用下面哪种修法了。
Rust 为什么要这样做
Section titled “Rust 为什么要这样做”在 Rust 里,很多方法并不属于类型本身,而是来自某个 trait。write_all 来自 Write trait,Stdout 实现了它。但 trait 的方法只有在文件里引入了这个 trait(通常是用一行 use)时才能用。这就是 “items from traits can only be used if the trait is in scope” 的意思。
这条规则让代码更容易预测。两个 crate 可能各自通过不同的 trait,给同一个类型加上叫 write_all 的方法。如果所有 trait 都始终生效,你就分不清一次调用指的是哪一个。有了这条规则,只有你导入的 trait 才算数。
其他几种原因来自 Rust 严格的类型系统。Option<&str> 不是 &str,所以它没有 &str 的方法。泛型 T 可以是任何类型,所以 Rust 只允许你调用 T 的约束所保证的方法。
修复 1:导入 trait
Section titled “修复 1:导入 trait”当 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(b"..." 是字节字符串,里面只能写 ASCII 字符,所以这里的文字保留英文。)
用 rand crate 时也会遇到同样的情况。没有导入的话,rng.random_range(1..=6) 会报错,rustc 会告诉你要引入哪个 trait:
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 里,这个 trait 叫 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>`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 方法,但它的 trait 约束没有满足,具体是 Vec<{integer}>: Iterator 这一条。
对于 filter 等一些方法,提示会更友好:rustc 会说 Vec<i32> “is not an iterator”(不是迭代器),并加上 help: call `.into_iter()` first(先调用 .into_iter())。原因相同,修法也相同。
Vec<{integer}>: Iterator 之所以“not satisfied”(不满足),是因为 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 加上 trait 约束
Section titled “修复 4:给泛型 T 加上 trait 约束”当错误说找不到方法的是 “for type parameter T”(类型参数 T)时,就用这个方法。在泛型函数里,Rust 只知道 T 的约束保证了什么。光秃秃的 T 什么都不保证,所以它没有任何方法。
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 的意思是:ToString 这个 trait 定义了 to_string,也许你需要用它来约束类型参数 T。加上 rustc 建议的约束。这样一来,只有能转换成字符串的类型才会被接受:
fn describe<T: ToString>(item: T) -> String { format!("[{}]", item.to_string())}
fn main() { println!("{}", describe(42)); println!("{}", describe("准备好了"));}输出:
[42][准备好了]- 拼写错误,或者用了别的语言里的方法名。 在
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`。修复:加上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()。
- E0425:cannot find value in this scope:看不到的是名字本身,而不是某个类型上的方法。
- E0277:未实现 trait:某个类型缺少函数或运算符需要的 trait。在泛型代码里经常和 E0599 一起出现。
- E0308:类型不匹配:在需要
T的地方给了Option<T>,或者反过来。 - E0382:使用已移动的值:把
.iter()换成.into_iter()之后常见的后续错误。 - 所有编译错误:完整列表,每个错误都附有简短说明。
小测验
1. rustc 提示 "items from traits can only be used if the trait is in scope"。你应该怎么做?
2. names.first().to_uppercase() 报了 E0599,类型是 Option<&&str>。为什么?
3. 你在 Vec<i32> 上调用 scores.filter(...),rustc 说 "Vec<i32> is not an iterator"。该怎么改?
得分: 0 / 3
- E0599 — Rust error codes index(英文):这个错误的官方说明。
- Trait:定义共同行为 — Rust 程序设计语言:trait 怎样给类型添加方法,以及 trait 约束是怎么工作的。
- 使用迭代器处理元素序列 — Rust 程序设计语言:
iter()、into_iter()以及map这类迭代器方法。 Option— Rust standard library(英文):从Option中取值的所有方法。- The Rust prelude — Rust standard library(英文):哪些 trait 始终在作用域内,以及为什么
Write不在其中。