我对 Rust 语言非常陌生,所以请耐心等待。
我正在用 Rust 实现一个图形数据结构。对于图中的每个节点(以及边 - 从这个片段中省略),我有一个结构“算法”(可能命名不好),它执行一些基于节点和边的逻辑。算法需要了解图的连通性,因此本身不能属于节点或边。它们基于特征多态性,尽管我计划稍后将其重构为枚举多态性。最后,我有一个求解器,它通过迭代图的节点并为其创建算法来工作。请注意,该示例经过大量精炼。
但是,我有两个问题。第一个是由于“算法”向量中 Boxed 结构的生命周期。
error: lifetime may not live long enough
--> main.rs:67:29
|
51 | impl<'a> Solver<'a> {
| -- lifetime `'a` defined here
...
63 | pub fn solve(&mut self) {
| - let's call the lifetime of this reference `'1`
...
67 | let algorithm = Box::new(MyAlgorithm {
| _____________________________^
68 | | graph: &mut self.graph,
69 | | });
| |______________^ assignment requires that `'1` must outlive `'a`
我已尽力向编译器指示 Algorithm 结构体的生命周期应保持在 Solver 结构体的生命周期内,但这并没有奏效。
完成其工作后,算法将需要更新图的节点和边,因此它需要对图对象的可变引用。然而,由于第二个可变借用,这当然是不正确的。
cannot borrow `self.graph` as mutable more than once at a time
second mutable borrow occurs here
下面是代码。
struct Node {
// Define the Node struct...
}
impl Node {
// Implement methods for Node...
}
struct Graph {
nodes: Vec<Node>,
}
impl Graph {
fn new() -> Self {
Graph {
nodes: Vec::new(),
// Initialize other fields...
}
}
}
trait BaseAlgorithm<'a> {
// Define the trait methods...
}
// Create a MyAlgorithm struct that takes a mutable reference to the graph
struct MyAlgorithm<'a> {
graph: &'a mut Graph,
}
impl<'a> BaseAlgorithm<'a> for MyAlgorithm<'a> {
// Implement the trait methods for MyAlgorithm...
}
struct Solver<'a> {
algorithms: Vec<Box<dyn BaseAlgorithm<'a> + 'a>>,
graph: Graph,
}
impl<'a> Solver<'a> {
fn new() -> Self {
Solver {
algorithms: Vec::new(),
graph: Graph::new(),
}
}
fn add_algorithm(&mut self, algorithm: Box<dyn BaseAlgorithm<'a> + 'a>) {
self.algorithms.push(algorithm);
}
pub fn solve(&mut self) {
// Loop over the nodes vector within Graph
for node in &mut self.graph.nodes {
// add an algorithm with a mutable reference to Graph
let algorithm = Box::new(MyAlgorithm {
graph: &mut self.graph,
});
self.add_algorithm(algorithm);
}
}
}
fn main() {
let mut solver = Solver::new();
solver.solve();
}
如果可以修复设计,那么我将非常感谢任何帮助实现这一目标。但是,如果设计无法修复,是否有惯用的 Rust 模式来实现此逻辑的要求?
这个问题的答案取决于这个问题:算法什么时候需要修改图?如果求解器一次仅使用一种算法,则可以将图作为参数传递给求解器在算法上调用的函数,而不是始终存储对其的可变引用。
如果算法确实需要在所有时间对图进行可变访问,那么
&mut
无法实现这一点。您将需要使用内部可变性以不同的方式提供可变性。如果程序是单线程的,则可以使用 RefCell
;如果是多线程的,则可以使用 Mutex
或 RwLock
。因此,您可以将图表存储为 RefCell<Graph>
。这使得即使您只有对 RefCell
的不可变引用,也可以可变地借用该图。然后,简单地将引用单元借用到每个算法(如Algorithm{ graph: &self.graph }
)中可能会起作用,但如果没有,您可以通过引入引用计数来使其起作用。这使您不必担心生命周期,因为对数据的所有引用都会被计数,并且当没有剩余引用时它将被删除。单线程的引用计数指针类型为 Rc
,多线程的引用计数指针类型为 Arc
。因此,您可以根据多线程情况将图表存储为 Rc<RefCell<Graph>>
或 Arc<RwLock<Graph>>
。现在,使用 Rc
或 Arc
,您可以调用 clone()
来获取第二个 Rc
或 Arc
指向与第一个相同的数据。如果该数据是内部可变的,例如 RefCell
、Mutex
或 RwLock
,那么您可以可变地借用其内容。