跳转到内容

Rust 编译错误详解

Rust 编译器报了一堆红色的错,却看不懂它到底想要什么?你来对地方了。每个 Rust 开发者都会遇到这些错误,常常一天好几次。好消息是:反复出现的错误其实就那么几个,认识它们之后,就一点也不可怕了。

下面每一页讲一个错误码:先给出真实的报错信息,再用大白话解释它的意思,最后给出可以直接在浏览器里运行的修复方法。

错误 编译器怎么说 用大白话说
E0382 borrow of moved value 你把一个值交出去了,之后又想再用它
E0502 cannot borrow as mutable because it is also borrowed as immutable 别人还在读一个值,你就去改它
E0499 cannot borrow as mutable more than once at a time 两个地方想同时修改同一个值
E0308 mismatched types 这里要的是一种类型,你给的却是另一种
E0277 the trait bound is not satisfied 某个类型做不到你要求的事(打印、比较、相加……)
E0106 missing lifetime specifier Rust 不知道返回的引用能有效多久
E0425 cannot find value in this scope 名字拼错了,或者在它所在的代码块之外使用了它
E0599 no method named … found 这个类型上没有这个方法,或者没有导入提供它的 trait
E0384 cannot assign twice to immutable variable 你修改了一个没有声明 mut 的变量
E0596 cannot borrow as mutable, as it is not declared as mutable 你想通过一个不是 mut 的变量或引用去修改值
E0597 borrowed value does not live long enough 引用指向的值已经没了,引用却还在使用
E0515 cannot return reference to local variable 你返回了一个指向局部变量的引用,而它在函数结束时就被丢弃了
E0373 closure may outlive the current function, but it borrows … 闭包(常见于线程)借用了一个局部变量,而闭包运行时它可能已经不在了
E0369 binary operation == cannot be applied to type … 你的类型(还)不支持 ==、<、+ 这类运算符
E0432 unresolved import use 语句指向的 crate、模块或条目找不到
E0433 cannot find type … in this scope (older: failed to resolve) 像 HashMap::new() 这样的路径用到了没导入或不存在的名字
E0424 self value is a keyword only available in methods with a self parameter 你在一个不接收 self 的函数里用了 self
E0061 this function takes N arguments but M arguments were supplied 参数传多了或传少了(Rust 没有可选参数)
E0594 cannot assign to p.hp, as p is not declared as mutable 没有 mut 权限,却修改了字段或 & 后面的值
E0004 non-exhaustive patterns: X not covered 你的 match 没有覆盖所有可能的值
E0507 cannot move out of x which is behind a shared reference 你想拿走一个只是借来的值的所有权
E0603 function x is private 你用了一个不是 pub 的函数、结构体或模块
E0716 temporary value dropped while borrowed 你保留了一个临时值的引用,而这个值在这一行结束时就被扔掉了
E0463 can’t find crate for x 某个 crate(或某个目标平台的标准库)没有安装
E0368 binary assignment operation += cannot be applied to type … 你的类型不支持 +=、-= 这类运算符
E0057 this function takes N arguments but M were supplied (note: closure defined here) 调用闭包时参数传多了或传少了
E0282 type annotations needed Rust 自己推断不出类型,需要你写明
E0609 no field x on type T 字段名拼错了,或者值被包了一层(比如在 Option 里)
E0593 closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments 这里需要一个接收元组(或别的参数个数)的闭包,你的闭包却接收了几个单独的参数
E0631 type mismatch in closure arguments 闭包参数的类型和实际收到的不一致(常见的是 i32 和 &i32)
E0005 refutable pattern in local binding let Some(x) = … 可能匹配失败,所以普通的 let 不接受它
E0615 attempted to take value of method len on type String 你写成了 s.len,而不是 s.len()
E0610 {integer} is a primitive type and therefore doesn’t have fields 你在数字、bool 或 char 上用了 .field
E0560 struct User has no field named nmae 结构体字面量里用了一个结构体没有的字段名
E0616 field balance of struct Account is private 你在模块外读取了一个不是 pub 的字段
E0451 field x of struct Y is private 你用字面量创建结构体,但它有些字段是私有的
E0624 method x is private 你调用了一个不是 pub 的方法或关联函数
E0283 type annotations needed (cannot infer type … multiple impls satisfy this bound) 好几种类型都说得通(比如 .collect()、.sum()),你得选一个
E0284 type annotations needed: cannot satisfy <_ as FromStr>::Err == _ "42".parse() 不知道要解析成哪种类型
E0790 cannot call associated function on trait without specifying the corresponding impl type 你写了 Default::default() 或 Trait::new(),却没说是哪个类型
E0559 variant Shape::Circle has no field named r 枚举变体的字面量用了一个变体没有的字段名
E0063 missing field email in initializer of User 创建结构体时漏掉了一个或多个字段
E0689 can’t call method pow on ambiguous numeric type {integer} 2.pow(10) 或 2.0.sqrt() 需要一个具体的数字类型,比如 i32 或 f64
E0034 multiple applicable items in scope 两个 trait 给你的类型提供了同名方法,Rust 不知道该选哪个
E0412 cannot find type X in this scope (Rust 1.93+ prints E0425) 类型名拼错了、没导入或者没声明
E0428 the name area is defined multiple times 两个条目用了同一个名字;Rust 没有函数重载
E0026 variant Shape::Circle does not have a field named r 模式里写了一个结构体或变体没有的字段
E0027 pattern does not mention fields id, paid 结构体模式漏掉了字段;把它们补上,或者用 .. 结尾
E0533 expected unit struct, unit variant or constant, found struct variant Shape::Circle 在需要普通名字的地方用了结构体变体(或函数);加上 { .. }
E0592 duplicate definitions with name reset 两个 impl 块定义了同名的方法
E0255 the name Error is defined multiple times use 导入的名字和你自己的类型或函数重名了
E0252 the name Result is defined multiple times 两行 use 导入了同一个名字;用 as 给其中一个改名
E0411 cannot find type Self in this scope 你在 impl 或 trait 之外用了 Self
E0405 cannot find trait Display in this scope trait 名拼错了或者没导入(比如 use std::fmt::Display;)
E0532 expected unit struct, unit variant or constant, found tuple variant Shape::Circle 模式里写元组变体(或结构体)时漏了 ( ),或者在不该加的地方加了 ( )
E0164 expected tuple struct or tuple variant, found struct variant Shape::Circle 模式在结构体变体或关联条目上用了 ( );改用 { } 或匹配守卫
E0404 expected trait, found derive macro Debug 你写了 impl X for 或 T: X,但 X 是结构体、类型别名或没导入的派生宏
E0401 can’t use generic parameters from outer item 内部的 fn 用了外层函数的 T 或 Self;给它自己的泛型,或者改用闭包
E0107 enum takes 2 generic arguments but 1 generic argument was supplied Result<u32>、HashMap<String> 这类写法:< > 里的参数太少或太多
E0530 match bindings cannot shadow tuple variants 像 Circle => 这样光秃秃的变体名(在 use Shape::* 之后)不能当作新变量
E0434 can’t capture dynamic environment in a fn item 内部的 fn 看不到外层的局部变量;改用闭包,或者把它们作为参数传进去
E0601 main function not found in crate main 二进制程序里没有 fn main()(漏写、拼错、放进了 mod 里,或者它其实是个库)
E0658 use of unstable library feature iter_intersperse 你在 stable 版 Rust 上用了只有 nightly 才有的 API;换成稳定的替代写法,或者升级
E0614 type u32 cannot be dereferenced 你写了 *x,但 x 本来就是普通的值,不是引用
E0435 attempt to use a non-constant value in a constant const、数组长度或 static 用到了 let 变量;把它改成 const,或者改用 Vec
E0554 #![feature] may not be used on the stable release channel 复制来的代码只能在 nightly 上用;删掉这个属性改用稳定的 API,或者有意识地使用 nightly

Rust 的错误信息以友好著称,但信息量也很大。来看一个真实的例子:

fn main() {
let name = String::from("Ferris");
let greeting = name;
println!("{name}");
}
error[E0382]: borrow of moved value: `name`
--> src/main.rs:4:16
|
2 | let name = String::from("Ferris");
| ---- move occurs because `name` has type `String`, which does not implement the `Copy` trait
3 | let greeting = name;
| ---- value moved here
4 | println!("{name}");
| ^^^^ value borrowed here after move
|
help: consider cloning the value if the performance cost is acceptable
|
3 | let greeting = name.clone();
| ++++++++

按这个顺序读:

  1. 第一行是摘要:错误码(E0382)加一句话的描述。
  2. 箭头那一行(--> src/main.rs:4:16)告诉你出错的文件、行号和列号。
  3. ^^^^ 标记指向出错的确切位置。---- 标记讲的是前因后果。这个例子里它们在说:值在第 2 行创建,在第 3 行被移动,然后在第 4 行被使用。
  4. help: 是编译器建议的修复方法,常常直接给出要加的代码(++++ 标记的是新加的字符)。它不一定是最好的修复,但是个很好的起点。

从第一个错误开始读。一个错误可能引发一连串后续错误,修好第一个,后面的往往就跟着消失了。

  • 让编译器多讲一点。 每个错误码都内置了一份更长的解释。在终端里运行:

    Terminal window
    rustc --explain E0382

    你会看到一段简短的说明、一个出错的例子和一个修好的例子(说明是英文的)。

  • 经常检查。 cargo check 不用构建整个程序就能找出错误,所以比 cargo build 快得多。每写几行就运行一次,你一次只会遇到一个错误,而不是二十个。参见 Cargo 与 crate。

  • 让编辑器在你打字时就显示错误。 装上 rust-analyzer 扩展后,错误会直接显示在代码里,附带同样的 help 文字。参见 Rust 工具与环境配置。

这些错误大多存在的原因是:别的语言要到运行时才会发现(甚至永远发现不了)的问题,Rust 在程序运行之前就检查了:使用已经释放的内存、两个线程同时修改同一份数据、忘了检查 null。你每修好一个错误,就少了一个会跑到用户那里的 bug。

所以很多人说:在 Rust 里,仗都在编译时打完了,之后程序就能顺顺当当地跑起来。最常见的那些错误背后的规则,在所有权、借用和生命周期这几页里有详细讲解。

小测验

1. Rust 报了好几个错误。应该先修哪一个?

2. rustc --explain E0382 有什么作用?

3. 在错误信息里,^^^^ 标记表示什么?

得分: 0 / 3