关于Rust中切片场景下所有权规则违反的疑问
为什么这段Rust代码会触发E0502错误?
你对代码的核心误解有两点,我们逐一拆解:
1. 返回的&str并没有脱离原String的借用关系
你以为传给first_word的&s在函数返回后就销毁了,但实际上Rust的引用生命周期是绑定的。first_word的签名会被编译器自动推断为带生命周期标注的版本:
fn first_word<'a>(s: &'a String) -> &'a str { // 函数体不变 }
这意味着返回的&str(也就是word)和输入的&String共享同一个生命周期——word本质上还是对原String s的不可变借用,它的“有效时间”会延续到自己最后一次被使用的地方(也就是第20行的println!)。
2. word和clear的&mut self指向的是同一个底层对象
String的内部结构包含指向字符缓冲区的指针,word作为切片引用的就是这块缓冲区;而s.clear()调用时,clear方法需要获取&mut self——也就是对整个String的可变借用,最终操作的也是同一块缓冲区。Rust的借用规则管的是对同一个对象的借用冲突,不管你借的是整个对象还是它的一部分。
错误的本质
- 第16行:
let word = first_word(&s);创建了对s的不可变借用,这个借用的生命周期延续到第20行word被使用完毕。 - 第18行:
s.clear();尝试获取s的可变借用,此时不可变借用还未失效,直接违反了Rust的核心规则:同一时间,一个对象不能同时存在可变借用和不可变借用。
修复方案
方案1:提前结束不可变借用
把println!移到clear前面,让word的使用先完成,不可变借用失效后再操作可变引用:
fn main() { let mut s = String::from("hello world"); let word = first_word(&s); println!("the first word is: {}", word); s.clear(); }
方案2:复制为独立的String
如果需要在clear后仍保留word的内容,可以把切片复制成新的String,彻底脱离对原对象的依赖:
fn main() { let mut s = String::from("hello world"); let word = first_word(&s).to_string(); s.clear(); println!("the first word is: {}", word); }
内容的提问来源于stack exchange,提问作者Manseej Khatri
相关产品推荐
相关产品推荐

