我正在学习 rust ,我不太明白为什么这是行不通的。
#[derive(Debug)]
struct Node {
value: String,
}
#[derive(Debug)]
pub struct Graph {
nodes: Vec<Box<Node>>,
}
fn mk_node(value: String) -> Node {
Node { value }
}
pub fn mk_graph() -> Graph {
Graph { nodes: vec![] }
}
impl Graph {
fn add_node(&mut self, value: String) {
if let None = self.nodes.iter().position(|node| node.value == value) {
let node = Box::new(mk_node(value));
self.nodes.push(node);
};
}
fn get_node_by_value(&self, value: &str) -> Option<&Node> {
match self.nodes.iter().position(|node| node.value == *value) {
None => None,
Some(idx) => self.nodes.get(idx).map(|n| &**n),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn some_test() {
let mut graph = mk_graph();
graph.add_node("source".to_string());
graph.add_node("destination".to_string());
let source = graph.get_node_by_value("source").unwrap();
let dest = graph.get_node_by_value("destination").unwrap();
graph.add_node("destination".to_string());
}
}
(playground)
这有错误
error[E0502]: cannot borrow `graph` as mutable because it is also borrowed as immutable
--> src/main.rs:50:9
|
47 | let source = graph.get_node_by_value("source").unwrap();
| ----- immutable borrow occurs here
...
50 | graph.add_node("destination".to_string());
| ^^^^^ mutable borrow occurs here
51 | }
| - immutable borrow ends here
这个来自 * Programming Rust * 的例子与我的例子非常相似,但它确实有效:
pub struct Queue {
older: Vec<char>, // older elements, eldest last.
younger: Vec<char>, // younger elements, youngest last.
}
impl Queue {
/// Push a character onto the back of a queue.
pub fn push(&mut self, c: char) {
self.younger.push(c);
}
/// Pop a character off the front of a queue. Return `Some(c)` if there /// was a character to pop, or `None` if the queue was empty.
pub fn pop(&mut self) -> Option<char> {
if self.older.is_empty() {
if self.younger.is_empty() {
return None;
}
// Bring the elements in younger over to older, and put them in // the promised order.
use std::mem::swap;
swap(&mut self.older, &mut self.younger);
self.older.reverse();
}
// Now older is guaranteed to have something. Vec's pop method // already returns an Option, so we're set.
self.older.pop()
}
pub fn split(self) -> (Vec<char>, Vec<char>) {
(self.older, self.younger)
}
}
pub fn main() {
let mut q = Queue {
older: Vec::new(),
younger: Vec::new(),
};
q.push('P');
q.push('D');
assert_eq!(q.pop(), Some('P'));
q.push('X');
let (older, younger) = q.split(); // q is now uninitialized.
assert_eq!(older, vec!['D']);
assert_eq!(younger, vec!['X']);
}
3条答案
按热度按时间q5iwbnjs1#
您的问题的MRE可以简化为:
您遇到了Rust设计要防止的 * 确切问题 *。您有一个指向向量的引用,并试图插入向量。这样做可能需要重新分配向量的内存,使任何现有引用无效。如果发生这种情况,并且您使用了
item
中的值,您将访问未初始化的内存,可能导致崩溃。在这个特殊的例子中,你实际上并没有使用
item
(或者source
,在原始的例子中),所以你可以......不调用那一行,我假设你这样做是出于某种原因,所以你可以把引用 Package 在一个块中,这样在你试图再次改变值之前,它们就消失了:在现代的Rust中已经不需要这个技巧了,因为non-lexical lifetimes已经实现了,但是潜在的限制仍然存在--你不能在有其他引用的情况下拥有一个可变的引用。这是 * The Rust Programming Language * 中介绍的引用规则之一。
在其他情况下,您可以复制或克隆向量中的值。该项将不再是引用,您可以根据需要修改向量:
如果你的类型是不可克隆的,你可以把它转换成一个引用计数的值(比如
Rc
或Arc
),然后再克隆它。你可能需要也可能不需要使用interior mutability:这个来自编程生 rust 的例子非常相似
不,它不是,因为它根本不使用引用。
另请参见
*x
as mutable because it is also borrowed as immutablel3zydbqr2#
试着把你的不可变借位放在一个块{...}里面。这会在块之后结束借位。
pdkcd3nj3#
因此,对于任何其他人的头上撞到这个问题,并希望快速的出路-使用克隆而不是引用。例如,我正在迭代这个单元格列表,并希望改变一个属性
然后,我可以通过循环来修改这些值:
使用
Vec<&BoardCell>
只会产生这个错误。不知道这有多生 rust ,但嘿,它工作。