I tried to design a trait that can be implemented for any tree so that I can adapt it to any tree from other crates to perform traversal operations on it. I have come up with something like this
// I could make this dyn compatible later
pub trait NodeView: Sized {
// Some tree may error like fs::read_dir()
type Err;
type ChildIter<'c>: Iterator<Item = Result<Self, Self::Err>> + 'c
where
Self: 'c;
fn children<'c>(&'c self) -> Result<Self::ChildIter<'c>, Self::Err>;
fn parent(&self) -> Result<Option<Self>, Self::Err>;
}
But I encountered lifetime error:
fn dfs_api_test<T: NodeView>(a: T)
where
T::Err: Debug,
T: Debug,
{
let c = a.children().unwrap();
let mut stack = vec![];
stack.push(c);
while let Some(cur) = stack.pop() {
for item in cur {
let node = item.unwrap();
// Do something with node...
println!("We visited a node: {node:?}");
let c = node.children().unwrap();
stack.push(c);
}
}
}
error[E0597]: `node` does not live long enough
--> tree_ast\src\lib.rs:80:21
|
75 | while let Some(cur) = stack.pop() {
| ----- borrow later used here
76 | for item in cur {
77 | let node = item.unwrap();
| ---- binding `node` declared here
...
80 | let c = node.children().unwrap();
| ^^^^ borrowed value does not live long enough
81 | stack.push(c);
82 | }
| - `node` dropped here while still borrowed
From my understanding, basically it is required that node
have to be alive as long as c
.
I tried to do something similar with a concrete type:
struct Node {
value: String,
children: Vec<Node>,
}
struct Descendants<'a> {
stack: Vec<std::slice::Iter<'a, Node>>,
}
impl<'a> Iterator for Descendants<'a> {
type Item = &'a Node;
fn next(&mut self) -> Option<Self::Item> {
while let Some(top_iter) = self.stack.last_mut() {
if let Some(node) = top_iter.next() {
if !node.children.is_empty() {
let c = &node.children; // Important part here
let iter = c.iter();
self.stack.push(iter);
}
return Some(node);
} else {
self.stack.pop();
}
}
None
}
}
In this snippet iter
when expressed using opaque type, it should be impl Iterator + 'a
// Code from std
pub fn iter(&self) -> Iter<'_, T> {
Iter::new(self)
}
However, self.stack.push(iter);
complies without error. How is it allowed?
And in general, what is a good trait definition to generalize any tree-like data structure to traverse them?