Rust中无法借用*self,如何无需克隆字符串实现函数功能?
Rust 借用冲突问题解决
问题代码
struct Foo { stack: Vec<String>, } impl Foo { pub fn bar(&mut self) { // find condition here is for example only. // position in the stack is important. if let Some(s) = self.stack.iter().find(|x| x.is_ascii()) { self.baz(s.as_str()); } } fn baz(&mut self, _input: &str) { // mutating of `self.stack` and some other fields. } }
编译错误
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable --> src/main.rs:8:13 | 7 | if let Some(s) = self.stack.last() { | ----------------- immutable borrow occurs here 8 | self.baz(s.as_str()); | ^^^^^---^^^^^^^^^^^^ | | | | | immutable borrow later used by call | mutable borrow occurs here
核心原因
self.stack.iter().find会创建对self.stack的不可变借用,该借用的生命周期覆盖了self.baz的调用过程。而baz需要对self的可变借用,Rust借用检查器禁止同一对象同时存在可变与不可变借用,因此触发错误。
解决方案
方案1:使用原始指针(unsafe,需保证内存安全)
该方法无需克隆字符串,直接保留原字符串的借用,但需要手动保证baz执行期间,目标字符串不会被移动、修改或释放(比如baz不会删除该元素、不会导致Vec扩容重新分配内存)。
impl Foo { pub fn bar(&mut self) { // 一次性找到目标字符串,保存其指针和长度 let target = self.stack.iter() .find(|x| x.is_ascii()) .map(|s| (s.as_str().as_ptr(), s.as_str().len())); if let Some((ptr, len)) = target { // 转换回&str,unsafe操作需自行保证内存安全 let s = unsafe { std::str::from_utf8_unchecked(std::slice::from_raw_parts(ptr, len)) }; // 此时self的不可变借用已释放,可以安全调用可变方法 self.baz(s); } } fn baz(&mut self, _input: &str) { // 可以修改self.stack或其他字段,需确保目标字符串未被破坏 } }
方案2:使用引用计数(安全,无克隆字符串内容)
如果允许修改Foo的结构,将stack的元素改为Rc<String>,通过浅克隆引用计数指针获取独立于self的字符串引用,避免借用冲突。这种方式仅增加引用计数,不会克隆字符串内容:
use std::rc::Rc; struct Foo { stack: Vec<Rc<String>>, } impl Foo { pub fn bar(&mut self) { if let Some(s_rc) = self.stack.iter().find(|x| x.is_ascii()).cloned() { self.baz(s_rc.as_str()); } } fn baz(&mut self, _input: &str) { // 可以安全修改self.stack或其他字段 } }
注意事项
- 方案1的unsafe代码需严格遵守内存安全规则:若
baz修改stack导致目标字符串内存失效(如弹出元素、Vec扩容),会触发未定义行为。 - 方案2的
Rc会带来轻微的引用计数开销,但完全安全,且符合“不克隆字符串内容”的要求。
内容的提问来源于stack exchange,提问作者some_engineer
相关产品推荐
相关产品推荐

