为什么 unwrap_or() 在范围内保留借用?
Why does unwrap_or() keep borrow in scope?
正在尝试编译:
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()
),我实际上无法找到成功执行此操作的方法。
问题是 你 知道,凭借其语义,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)
如何使迭代器无效,这就是编译器阻止它的原因。
借用至少对整个语句有效。不幸的是,将 Option
拉出到单独的语句中的通常解决方案无济于事,因为它仍将包含一个可变引用(在 Some
中),这也迫使向量的借用被扩展.这在使用 find()
时似乎是不可避免的。编译器担心指向 Vector 存储的指针在某处浮动,并且可能会因推入 vector 而无效(这可能导致重新分配)。这不仅包括返回的 Option
中的指针,还包括可以由其中一个函数在内部创建的指针。如果不是因为没有 "hidden" 指针并且您仅在 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
获取索引然后用它建立索引只是 正确的 因为向量在两者之间没有(实质上)修改。
正在尝试编译:
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()
),我实际上无法找到成功执行此操作的方法。
问题是 你 知道,凭借其语义,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)
如何使迭代器无效,这就是编译器阻止它的原因。
借用至少对整个语句有效。不幸的是,将 Option
拉出到单独的语句中的通常解决方案无济于事,因为它仍将包含一个可变引用(在 Some
中),这也迫使向量的借用被扩展.这在使用 find()
时似乎是不可避免的。编译器担心指向 Vector 存储的指针在某处浮动,并且可能会因推入 vector 而无效(这可能导致重新分配)。这不仅包括返回的 Option
中的指针,还包括可以由其中一个函数在内部创建的指针。如果不是因为没有 "hidden" 指针并且您仅在 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
获取索引然后用它建立索引只是 正确的 因为向量在两者之间没有(实质上)修改。