尝试编译:
fn main() {
let mut vec = vec![1, 2, 3];
let four: &mut u32 = borrow_or_add(&mut vec, 4);
}
fn borrow_or_add(vec: &mut Vec<u32>, val: u32) -> &mut u32 {
vec.iter_mut().find(|v| **v == val).unwrap_or({
vec.push(val);
vec.last_mut().unwrap()
})
}
...给出以下结果:
q.rs:8:9: 8:12 error: cannot borrow `*vec` as mutable more than once at a time
q.rs:8 vec.push(val);
^~~
q.rs:7:5: 7:8 note: previous borrow of `*vec` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `*vec` until the borrow ends
q.rs:7 vec.iter_mut().find(|v| **v == val).unwrap_or({
^~~
q.rs:12:2: 12:2 note: previous borrow ends here
q.rs:6 fn borrow_or_add(vec: &mut Vec<u32>, val: u32) -> &mut u32 {
...
q.rs:12 }
^
q.rs:10:9: 10:12 error: cannot borrow `*vec` as mutable more than once at a time
q.rs:10 vec.last_mut().unwrap()
^~~
q.rs:7:5: 7:8 note: previous borrow of `*vec` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `*vec` until the borrow ends
q.rs:7 vec.iter_mut().find(|v| **v == val).unwrap_or({
^~~
q.rs:12:2: 12:2 note: previous borrow ends here
q.rs:6 fn borrow_or_add(vec: &mut Vec<u32>, val: u32) -> &mut u32 {
...
q.rs:12 }
^
q.rs:10:9: 10:12 error: cannot borrow `*vec` as mutable more than once at a time
q.rs:10 vec.last_mut().unwrap()
^~~
q.rs:7:5: 7:8 note: previous borrow of `*vec` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `*vec` until the borrow ends
q.rs:7 vec.iter_mut().find(|v| **v == val).unwrap_or({
^~~
q.rs:12:2: 12:2 note: previous borrow ends here
q.rs:6 fn borrow_or_add(vec: &mut Vec<u32>, val: u32) -> &mut u32 {
...
q.rs:12 }
^
据我所知,unwrap_or()
的主体不能引用上述vec
的借用,为什么不从范围中删除呢?有没有一种优雅的方式来实现这个功能?实际上,我无法在不使用两遍和bool
(即contains()
)的情况下找到成功完成此操作的方法。
答案 0 :(得分:7)
至少在整个声明中借用是有效的。不幸的是,将Option
拉出到单独的语句中的通常解决方案将无济于事,因为它仍然包含一个可变引用(在Some
中),它强制借用向量来扩展。使用find()
时,这似乎是不可避免的。编译器担心指向Vector存储的指针在某处浮动,并且可能通过推入向量(这可能导致重新分配)而无效。这不仅包括返回的Option
中的指针,还包括可由其中一个函数内部生成的指针。这是一个非常有效的问题,如果不是因为没有“隐藏”指针而你只在Option
不是指针时推送。生命周期系统的细微程度不足以捕获这一事实,我没有看到一种简单的方法来修复它或解决它。
您可以使用position
来查找索引:
fn borrow_or_add(vec: &mut Vec<u32>, val: u32) -> &mut u32 {
match vec.iter().position(|&v| v == val) {
Some(i) => &mut vec[i],
None => {
vec.push(val);
vec.last_mut().unwrap()
}
}
}
请注意,向量中的索引本质上是美化指针。如果向量发生变化,它们可以开始引用错误的元素,尽管它们不能在重新分配时变得悬空,而无效的索引(大于最大的有效索引)将导致恐慌而不是内存不安全。仍然,从position
获取索引,然后使用它进行索引只是正确,因为矢量在其间没有(基本上)修改过。
答案 1 :(得分:0)
问题是你凭借其语义知道vec.iter_mut().find().unwrap_or()
会忽略它来自vec
的任何内容。但是,编译器不知道这一点。实际上,方法调用链可以很好地存储来自迭代器的值,直到由unwrap_or()
调用的闭包。请参阅此常见方案,该方案具有与您的示例类似的模拟结构:
let mut vec: Vec<i32> = vec![3, 2, 5];
vec.iter().map(|&i| {
vec.push(i+1)
}).last();
此处vec.iter_mut().find().unwrap_or()
刚刚被vec.iter().map()
取代。正如您所看到的,vec
中的值可以在整个方法调用中借用。在后一个例子中很明显vec.push(i+1)
如何使迭代器无效,这就是编译器阻止它的原因。