我正在尝试实现一个使用借用检查/生命周期的系统,以便为集合提供安全的自定义索引.请考虑以下代码:
struct Graph(i32); struct Edge<'a>(&'a Graph, i32); impl Graph { pub fn get_edge(&self) -> Edge { Edge(&self, 0) } pub fn split(&mut self, Edge(_, edge_id): Edge) { self.0 = self.0 + edge_id; } pub fn join(&mut self, Edge(_, edge0_id): Edge, Edge(_, edge1_id): Edge) { self.0 = self.0 + edge0_id + edge1_id; } } fn main() { let mut graph = Graph(0); let edge = graph.get_edge(); graph.split(edge) }
Edge
当调用诸如split
或join
调用方法时,应删除对结构借用的图形的引用.这将满足API不变量,即在图形变异时必须销毁所有边缘索引.但是,编译器没有得到它.它失败的消息就像
error[E0502]: cannot borrow `graph` as mutable because it is also borrowed as immutable
--> src/main.rs:23:5
|
22 | let edge = graph.get_edge();
| ----- immutable borrow occurs here
23 | graph.split(edge)
| ^^^^^ mutable borrow occurs here
24 | }
| - immutable borrow ends here
如果我理解正确,编译器就无法意识到在调用函数时实际上正在释放边缘结构中发生的图形的借用.有没有办法教我编译器在这里尝试做什么?
奖金问题:有没有办法完全相同但没有实际借用Edge
结构中的图形?边缘结构仅用作遍历的临时目的,并且永远不会成为外部对象状态的一部分(我的边缘有'弱'版本).
附录:经过一番挖掘,似乎真的很琐碎.首先,Edge(_, edge_id)
实际上并没有对结构进行解构Edge
,因为_
根本没有绑定(是的,i32
复制使事情变得更加复杂,但这很容易通过将其包装到非复制结构中来解决).其次,即使我完全解构Edge
(即通过在单独的范围内进行),对图形的引用仍然存在,即使它应该被移动(这必定是一个bug).它只有在我在单独的函数中执行解构时才有效.现在,我知道如何绕过它(通过一个单独的对象描述状态变化并在提供索引时对其进行解构),但这很快变得非常尴尬.