E0382
error[E0382]: use of moved value: `s1`
当你把堆分配的值(如 String 或 Vec)赋给另一个变量时,所有权转移到新变量,原变量不再有效——你无法继续使用它。这是 Rust 所有权系统在编译期消除"释放后使用"Bug 的机制。
❌ Broken
let s1 = String::from("hello");
let s2 = s1; // s1 moves into s2
println!("{}", s1); // ❌ E0382: s1 was moved✅ Fixed
let s1 = String::from("hello");
let s2 = s1.clone(); // deep copy — both stay valid
println!("{} {}", s1, s2); // ✅
// Or borrow instead of moving:
let s2 = &s1;
println!("{} {}", s1, s2); // ✅💡 Tip: 基本类型(i32、bool、char、f64)实现了 Copy,会自动复制。堆类型(String、Vec、Box)则会移动。
E0502
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
Rust 允许多个共享引用(&)或一个独占可变引用(&mut)——两者不能同时存在。如果你持有活跃的不可变借用,在它结束之前不能再取得可变借用。这条规则从根本上消除了数据竞争。
❌ Broken
let mut v = vec![1, 2, 3];
let first = &v[0]; // immutable borrow
v.push(4); // ❌ E0502: mutable borrow while immutable exists
println!("{}", first);✅ Fixed
let mut v = vec![1, 2, 3];
let first = v[0]; // copy the value out (i32 is Copy)
v.push(4); // ✅ no active borrow
println!("{}", first);
// Or restructure scope:
let mut v = vec![1, 2, 3];
{
let first = &v[0];
println!("{}", first);
} // first's borrow ends here
v.push(4); // ✅💡 Tip: 借用检查器比较保守。如果它一直报错,可以尝试把 println 移到前面、复制值而非借用,或使用 .clone()。
E0499
error[E0499]: cannot borrow `v` as mutable more than once at a time
同一时刻只能存在一个可变引用(&mut)。这防止了单线程代码中的数据竞争,也是 Rust 并发保证的基础规则。
❌ Broken
let mut v = vec![1, 2, 3];
let a = &mut v;
let b = &mut v; // ❌ E0499: second mutable borrow
a.push(4);
b.push(5);
✅ Fixed
let mut v = vec![1, 2, 3];
{
let a = &mut v;
a.push(4);
} // a's borrow ends here
let b = &mut v; // ✅ now safe
b.push(5);💡 Tip: 使用作用域块 {} 来限制可变借用的存活时间。实践中这个错误通常意味着需要重构逻辑,使可变操作顺序发生。
E0308
error[E0308]: mismatched types
expected `i32`, found `&i32`
编译器推断或期望的类型与你提供的不符。在迭代时(迭代器产生引用)、函数返回 () 而非实际值时,或混用有符号/无符号整数时非常常见。
❌ Broken
// Trailing semicolon returns () instead of i32:
fn double(n: i32) -> i32 {
n * 2; // ❌ E0308: returns () not i32
}
// Iterator reference confusion:
let nums = vec![1, 2, 3];
let sum: i32 = nums.iter().sum(); // needs type annotation✅ Fixed
fn double(n: i32) -> i32 {
n * 2 // ✅ no semicolon — expression returned
}
// Dereference in closures when iterating:
let nums = vec![1, 2, 3];
let doubled: Vec<i32> = nums.iter().map(|&x| x * 2).collect();
// ^ dereference the &i32💡 Tip: 函数最后一行末尾加分号会悄然将返回类型改为 ()。这是 Rust 中初学者最常犯的错误 #1。
E0277
error[E0277]: `MyType` doesn't implement `std::fmt::Display`
该类型没有实现所需的特征。最常见的触发场景:用 {} 格式化却没有实现 Display、比较类型却没有实现 PartialOrd、调用需要特定特征的方法。
❌ Broken
struct Point { x: i32, y: i32 }
let p = Point { x: 1, y: 2 };
println!("{}", p); // ❌ E0277: Point doesn't implement Display
println!("{:?}", p); // also fails — needs Debug✅ Fixed
#[derive(Debug)]
struct Point { x: i32, y: i32 }
let p = Point { x: 1, y: 2 };
println!("{:?}", p); // ✅ Debug via #[derive(Debug)]
// Implement Display manually for custom formatting:
use std::fmt;
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
println!("{}", p); // ✅💡 Tip: 为 {:?} 打印添加 #[derive(Debug)]。对于 {} 打印,需要手动实现 std::fmt::Display。大多数缺失的约束是 Debug、Display、Clone、PartialEq 或 PartialOrd。
E0106
error[E0106]: missing lifetime specifier
expected named lifetime parameter
当函数返回一个引用且有多个引用参数时,Rust 无法推断输出引用来自哪个输入。你需要用生命周期标注来告知编译器。
❌ Broken
// Compiler doesn't know if the return borrows from x or y:
fn longest(x: &str, y: &str) -> &str { // ❌ E0106
if x.len() > y.len() { x } else { y }
}✅ Fixed
// 'a says: output lives no longer than the shorter input
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { // ✅
if x.len() > y.len() { x } else { y }
}
// Single input → no annotation needed (elision rule):
fn first_word(s: &str) -> &str { // ✅ lifetime elided
let bytes = s.as_bytes();
for (i, &b) in bytes.iter().enumerate() {
if b == b' ' { return &s[..i]; }
}
&s[..]
}💡 Tip: 生命周期标注是约束,不是持续时间。'a 的含义是"输出的存活时间不超过输入"。大多数生命周期会被自动推断(省略)。只有当编译器无法确定关系时,才需要显式标注。
E0596
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
你试图修改一个未用 mut 声明的变量。在 Rust 中,变量默认不可变——编译器强制执行这一点,以便在编译期捕获意外的修改。
❌ Broken
let x = 5;
x = 10; // ❌ E0596: x is immutable
let v = vec![1, 2, 3];
v.push(4); // ❌ E0596: v is immutable
✅ Fixed
let mut x = 5; // ✅ mut makes it mutable
x = 10;
let mut v = vec![1, 2, 3];
v.push(4); // ✅
💡 Tip: 在 let 后面加上 mut。只有当变量确实需要改变时才加 mut——默认不可变能捕获 Bug,也让代码更易推理。
E0384
error[E0384]: cannot assign twice to immutable variable `x`
与 E0596 类似,但触发于第二次赋值而非方法调用。变量声明时没有 mut,却试图重新赋值。
❌ Broken
let x = 5;
x = 10; // ❌ E0384
✅ Fixed
let mut x = 5;
x = 10; // ✅
// Shadowing is another option if you want to "replace" the variable:
let x = 5;
let x = 10; // ✅ shadowing — creates a new binding named x
💡 Tip: 遮蔽(let x = ...)和可变(mut x = ...)看起来相似,但不同:遮蔽创建新变量(可以改变类型),可变性修改同一绑定。
E0507
error[E0507]: cannot move out of `*s` which is behind a shared reference
你试图从引用中移出一个值。你无法通过 &T 获取所有权——引用并不拥有数据。
❌ Broken
fn print_name(s: &String) {
let owned = *s; // ❌ E0507: can't move out of &String
println!("{}", owned);
}✅ Fixed
fn print_name(s: &String) {
let owned = s.clone(); // ✅ clone the data
println!("{}", owned);
}
// Or just use the reference directly:
fn print_name(s: &String) {
println!("{}", s); // ✅ no need to own it
}💡 Tip: 如果只需要读取值,直接使用引用即可。如果需要拥有的副本,调用 .clone()。如果需要所有权,将参数改为接受 T 而非 &T。
E0004
error[E0004]: non-exhaustive patterns: `None` not covered
match 表达式必须处理每一种可能的情况。如果有任何变体未被处理,代码无法编译。这消除了整类因未处理情况导致崩溃的运行时 Bug。
❌ Broken
let opt: Option<i32> = Some(42);
match opt {
Some(n) => println!("{}", n),
// ❌ E0004: None not covered
}✅ Fixed
match opt {
Some(n) => println!("{}", n),
None => println!("nothing"), // ✅ exhaustive
}
// Use _ as a catch-all:
match opt {
Some(n) => println!("{}", n),
_ => {}, // ✅ handles everything else
}
// Or use if let for a single case:
if let Some(n) = opt {
println!("{}", n); // ✅ no else needed
}💡 Tip: 编译器会精确告知哪些变体缺失。_ 是通配符。if let 是只关心一种模式时的简写。
E0072
error[E0072]: recursive type `List` has infinite size
如果递归类型的每个变体直接包含自身,分配它将需要无限内存。Rust 需要在编译期知道每种类型的大小。解决方法是通过 Box 进行间接引用,Box 的大小是已知的指针大小。
❌ Broken
enum List {
Cons(i32, List), // ❌ E0072: infinite size
Nil,
}✅ Fixed
enum List {
Cons(i32, Box<List>), // ✅ Box has fixed pointer size (8 bytes)
Nil,
}
let list = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));💡 Tip: Box<T> 是最简单的堆指针。无论 T 是什么,它都有固定大小(一个指针宽度),从而打破递归的大小计算。
E0716
error[E0716]: temporary value dropped while borrowed
你创建了一个临时值,获取了它的引用,但临时值在引用被使用之前就被释放了。引用将成为悬垂引用——指向已释放的内存。
❌ Broken
let s: &str = &String::from("hello")
.to_uppercase(); // ❌ E0716: temporary dropped
// Also common with chains:
let name = get_user().name; // if get_user() returns a temp✅ Fixed
// Bind the temporary to a variable first:
let upper = String::from("hello").to_uppercase();
let s: &str = &upper; // ✅ upper lives long enough
println!("{}", s);💡 Tip: 遇到此错误时,引入一个变量来持有中间值。let 绑定的生命周期延伸到所在块的结尾。
E0515
error[E0515]: cannot return value referencing local variable `local`
你试图返回指向局部变量的引用。函数返回时,局部变量被释放,引用将悬垂。Rust 在编译期阻止了这一点。
❌ Broken
fn get_greeting() -> &str {
let s = String::from("hello");
&s // ❌ E0515: s is dropped when function returns
}✅ Fixed
// Return an owned value:
fn get_greeting() -> String {
String::from("hello") // ✅ caller owns it
}
// Or return a &'static str literal:
fn get_greeting() -> &'static str {
"hello" // ✅ lives for the entire program
}💡 Tip: 如果需要返回引用,它必须来自函数的输入(从参数借用)或具有 'static 生命周期。有疑问时,返回拥有所有权的类型(String、Vec 等)。
E0369
error[E0369]: binary operation `>` cannot be applied to type `T`
你对泛型类型 T 使用了运算符,但 T 没有约束要求该运算符存在。泛型代码必须明确声明类型支持哪些操作。
❌ Broken
fn largest<T>(list: &[T]) -> &T {
let mut biggest = &list[0];
for item in list {
if item > biggest { // ❌ E0369: T doesn't implement PartialOrd
biggest = item;
}
}
biggest
}✅ Fixed
fn largest<T: PartialOrd>(list: &[T]) -> &T { // ✅ add bound
let mut biggest = &list[0];
for item in list {
if item > biggest {
biggest = item;
}
}
biggest
}💡 Tip: 遇到 E0369 时,错误信息会告诉你需要哪个特征:比较运算需要 PartialOrd,+ 运算需要 Add,{} 格式化需要 Display 等。将其添加为约束:<T: 特征名>。
E0428
error[E0428]: the name `connect` is defined multiple times
你在同一作用域内定义了两个同名的条目(函数、结构体、类型等)。Rust 不允许这样做——名称在模块内必须唯一。
❌ Broken
fn connect() -> String { "tcp".into() }
fn connect() -> String { "udp".into() } // ❌ E0428: duplicate✅ Fixed
fn connect_tcp() -> String { "tcp".into() }
fn connect_udp() -> String { "udp".into() } // ✅ unique names
// Or use a parameter:
fn connect(protocol: &str) -> String { protocol.into() }💡 Tip: use 语句导入冲突的名称时也会触发此错误。使用 as 重命名:use std::io::Error as IoError;
E0061
error[E0061]: this function takes 2 arguments but 3 arguments were supplied
你调用函数时传入的参数多于或少于其签名声明的数量。Rust 不支持默认参数或可变参数函数(宏如 println! 除外)。
❌ Broken
fn add(a: i32, b: i32) -> i32 { a + b }
add(1, 2, 3); // ❌ E0061: 3 args, expected 2
add(1); // ❌ E0061: 1 arg, expected 2✅ Fixed
add(1, 2); // ✅
// For optional parameters, use Option:
fn greet(name: &str, title: Option<&str>) {
match title {
Some(t) => println!("{} {}", t, name),
None => println!("{}", name),
}
}
greet("Alice", None);
greet("Bob", Some("Dr."));💡 Tip: Rust 没有默认参数。对可选值使用 Option<T>,对有许多可选字段的函数使用构建器结构体。
E0433
error[E0433]: failed to resolve: use of undeclared crate or module `HashMap`
你使用了不在当前作用域中的类型或函数。对于预导入之外的标准库类型(如 HashMap、BTreeMap、BufReader),你需要显式的 use 语句。
❌ Broken
let mut map = HashMap::new(); // ❌ E0433: HashMap not in scope
✅ Fixed
use std::collections::HashMap;
let mut map = HashMap::new(); // ✅
// Common imports:
use std::collections::{HashMap, HashSet, BTreeMap};
use std::io::{self, BufRead, Write};
use std::fmt;💡 Tip: Rust 预导入自动引入常用类型(Vec、String、Option、Result 等)。其他所有类型都需要显式 use。Rust Analyzer 会建议正确的 use 路径。
error: expected `;`, found `let`
error: expected expression, found keyword `fn`
语法错误——解析器遇到了意外内容。通常是缺少分号、未关闭的定界符、关键字拼写错误或错位的表达式。
❌ Broken
fn main() {
let x = 5 // ❌ missing semicolon
let y = 10;
fn inner() {} // ❌ nested fn needs to be at statement level
x + y // if this is a statement, not a return, add ;
}✅ Fixed
fn main() {
let x = 5; // ✅ semicolon added
let y = 10;
fn helper() {} // ✅ nested fn is valid in Rust
println!("{}", x + y);
}💡 Tip: Rust 的错误信息几乎总是指向正确的行。如果分号错误看起来位置不对,检查上一行——上一条语句缺少 ; 会让解析器进入奇怪的状态。
error[E0275]: overflow evaluating the requirement `Box<T>: Sized`
编译器在证明特征约束时陷入了无限循环。最常见的原因是递归的特征实现,或某个类型试图实现一个需要自身的特征。
❌ Broken
// Generic function calling itself with an incompatible bound:
fn process<T: Clone>(x: T) {
process(x.clone()); // infinite recursion in type inference
}✅ Fixed
// Add a base case or restructure logic:
fn process(x: String) {
if x.is_empty() { return; }
process(x[1..].to_string());
}💡 Tip: 这个错误几乎总是指向递归类型或特征约束循环。简化特征约束或添加显式类型参数。
error[E0425]: cannot find value `x` in this scope
你引用了一个在当前作用域中不存在的变量。常见原因:变量名拼写错误、变量在已结束的内部块中声明、在循环外使用了循环变量。
❌ Broken
{
let x = 5;
}
println!("{}", x); // ❌ x is out of scope
for i in 0..10 { }
println!("{}", i); // ❌ i only lives inside the for loop✅ Fixed
let x = 5; // declare outside the block
{
println!("{}", x); // ✅ x is in scope
}
println!("{}", x); // ✅ still in scope
// Save the last loop value explicitly:
let mut last = 0;
for i in 0..10 { last = i; }
println!("{}", last); // ✅💡 Tip: Rust 的作用域以块为基础。变量只存在于声明处到其所在块结尾之间。如果需要更宽的作用域,将声明移到外层。
🦀
准备好了吗?
26 个免费互动挑战。无需安装,无需注册,马上开始。
开始学习 Rust →