面试题答案
一键面试问题分析
- 变量作用域与闭包捕获:
- 在
main
函数中,count
是在data.process_with_closure
调用之前声明的。闭包|vec| { for _ in vec.iter() { count += 1; } }
尝试捕获并修改count
。在Rust中,闭包默认以不可变方式捕获外部变量,要修改count
,需要以可变方式捕获。 - 这里闭包捕获
count
的方式不符合修改count
的需求,导致编译错误。
- 在
- 所有权转移:
- 在
process_with_closure
方法中,sub_vec
是通过filter
收集创建的新Vec<i32>
。然后将sub_vec
传递给闭包closure
。最后,self.data
被赋值为sub_vec
。这一系列操作在所有权方面没有问题,因为sub_vec
的所有权被正确转移。
- 在
编译错误信息
编译时会出现类似于“cannot borrow count
as mutable because it is also borrowed as immutable”的错误。这是因为闭包默认以不可变方式捕获count
,但闭包内部尝试对其进行可变操作。
修改方案
-
以可变方式捕获
count
:- 可以使用
mut
关键字将闭包声明为可变闭包,这样闭包就能以可变方式捕获count
。
struct Data { data: Vec<i32> } impl Data { fn process_with_closure(&mut self, closure: impl FnMut(&mut Vec<i32>)) { let sub_vec: Vec<i32> = self.data.iter().filter(|&&x| x > 5).collect(); closure(&mut sub_vec); self.data = sub_vec; } } fn main() { let mut data = Data { data: vec![1, 2, 6, 4, 8] }; let mut count = 0; data.process_with_closure(move |vec| { for _ in vec.iter() { count += 1; } }); println!("Count: {}", count); }
- 这里使用
move
关键字,将count
的所有权转移到闭包中,确保闭包可以修改count
。这样修改后,代码能够正确编译和运行。
- 可以使用
-
另一种方式(使用
RefCell
):- 如果不想转移
count
的所有权,可以使用std::cell::RefCell
。RefCell
允许在运行时检查可变借用规则,即使在编译时不能确定借用关系。
use std::cell::RefCell; struct Data { data: Vec<i32> } impl Data { fn process_with_closure(&mut self, closure: impl FnMut(&mut Vec<i32>)) { let sub_vec: Vec<i32> = self.data.iter().filter(|&&x| x > 5).collect(); closure(&mut sub_vec); self.data = sub_vec; } } fn main() { let mut data = Data { data: vec![1, 2, 6, 4, 8] }; let count = RefCell::new(0); data.process_with_closure(|vec| { for _ in vec.iter() { let mut c = count.borrow_mut(); *c += 1; } }); println!("Count: {}", *count.borrow()); }
- 这种方式通过
RefCell
来管理count
的可变借用,在闭包中通过borrow_mut
获取可变引用,在需要读取时通过borrow
获取不可变引用。这样可以在不转移所有权的情况下实现对count
的修改。
- 如果不想转移