I'm trying to implement a Trie/Prefix Tree in Rust and I'm having trouble with the borrow checker. Here is my implementation so far and I'm getting an error when I call children.insert.
cannot borrow *children as mutable because it is also borrowed as immutable
use std::collections::HashMap;
#[derive(Clone, Debug)]
struct PrefixTree {
value: String,
children: HashMap<char, PrefixTree>
}
fn insert(mut tree: &mut PrefixTree, key: &str, value: String) {
let mut children = &mut tree.children;
for c in key.chars() {
if !children.contains_key(&c) {
children.insert(c, PrefixTree {
value: String::from(&value),
children: HashMap::new()
});
}
let subtree = children.get(&c);
match subtree {
Some(s) => {
children = &mut s.children;
},
_ => {}
}
}
tree.value = value;
}
fn main() {
let mut trie = PrefixTree {
value: String::new(),
children: HashMap::new()
};
let words = vec!["Abc", "Abca"];
for word in words.iter() {
insert(&mut trie, word, String::from("TEST"));
}
println!("{:#?}", trie);
}
I think this problem is related to Retrieve a mutable reference to a tree value but in my case I need to update the mutable reference and continue looping. I understand why I'm getting the error since I'm borrowing a mutable reference twice, but I'm stumped about how to rewrite this so I'm not doing it that way.
When you're doing multiple things with a single key (like find or insert and get) and run into borrow trouble, try using the Entry API (via .entry()):
fn insert(mut tree: &mut PrefixTree, key: &str, value: String) {
let mut children = &mut tree.children;
for c in key.chars() {
let tree = children.entry(c).or_insert_with(|| PrefixTree {
value: String::from(&value),
children: HashMap::new(),
});
children = &mut tree.children;
}
tree.value = value;
}
Related
This question already has answers here:
How to handle "temporary value dropped" error when adapting Box-based tree structure to Rc+RefCell?
(2 answers)
Closed last month.
I was following this other post: Understanding Rust `Rc<RefCell<_>>` where op tried implementing a tree with Box and was successful in doing it but then tried implementing it with Rc and RefCell and found issues. The accepted answer compiles but doesn't work because it doesn't add nodes to the root. I tried updating the accepted answer a bit to try and get it to work but wasn't able to. Basically I'm trying to get mutable references in the loop and I can't because I borroed an immutable reference. But then if a borrow_mut() I get that value is a private field, so I'm assuming I can't access any properties of the contained value if it is a mutable reference?
What should I do to get this code to work?
use std::borrow::BorrowMut;
use std::cell::RefCell;
use std::cmp::Ordering;
use std::rc::Rc;
use std::fmt;
#[derive(Debug, Clone)]
pub(crate) struct TreeBox<T> {
root: Option<Box<NodeBox<T>>>,
}
#[derive(Debug, Clone)]
struct NodeBox<T> {
value: T,
left: Option<Box<NodeBox<T>>>,
right: Option<Box<NodeBox<T>>>,
}
impl<T: Ord> TreeBox<T> {
fn new() -> Self {
Self { root: None }
}
pub fn insert(&mut self, value: T) -> bool {
let mut node = &mut self.root;
while let Option::Some(current_node) = node {
match current_node.value.cmp(&value) {
Ordering::Less => node = &mut current_node.right,
Ordering::Equal => return false,
Ordering::Greater => node = &mut current_node.left,
}
}
*node = Option::Some(Box::new(NodeBox {
value,
left: Option::None,
right: Option::None,
}));
return true;
}
}
#[derive(Debug, Clone)]
pub(crate) struct Tree<T> {
root: Option<Rc<RefCell<Node<T>>>>,
}
#[derive(Debug, Clone, PartialEq)]
struct Node<T> {
value: T,
left: Option<Rc<RefCell<Node<T>>>>,
right: Option<Rc<RefCell<Node<T>>>>,
}
impl<T: Ord + fmt::Debug> Tree<T> {
fn new() -> Self {
Self { root: None }
}
pub fn insert(&mut self, value: T) -> bool {
let mut node = &mut self.root;
while let Some(current_node) = node {
let current_node = current_node.borrow();
let cmp = current_node.value.cmp(&value);
let new_node = match cmp {
Ordering::Less => &mut current_node.left,
Ordering::Equal => return false,
Ordering::Greater => &mut current_node.right,
};
node = new_node;
}
// let mut node = &mut node;
*node = Some(Rc::new(RefCell::new(Node {
value,
left: None,
right: None,
})));
println!("node: {:?}", node);
true
}
}
fn main() {
let mut tree_box = TreeBox::new();
tree_box.insert(1);
tree_box.insert(2);
tree_box.insert(3);
let mut tree = Tree::new();
tree.insert(1);
tree.insert(2);
tree.insert(3);
println!("TreeBox: {:?}", tree_box);
println!("Tree: {:?}", tree);
}
The accepted answer compiles but doesn't work because it doesn't add nodes to the root.
You are right, and fixing the original solution, here a version that add the root node correctly:
pub fn insert(&mut self, value: T) -> bool {
//if no root, just create one
let mut node = if let Some(root) = &self.root {
Rc::clone(root)
} else {
self.root = Some(Rc::new(RefCell::new(Node {
value,
left: None,
right: None,
})));
return true;
};
loop {
let current_node = Rc::clone(&node);
let mut current_node = RefCell::borrow_mut(¤t_node);
let cmp = current_node.value.cmp(&value);
let next_node = match cmp {
Ordering::Less => &mut current_node.left,
Ordering::Equal => return false,
Ordering::Greater => &mut current_node.right,
};
if let Some(next_node) = next_node {
node = Rc::clone(next_node);
} else {
*next_node = Some(Rc::new(RefCell::new(Node {
value,
left: None,
right: None,
})));
println!("node: {:?}", node);
return true;
}
}
}
Basically I'm trying to get mutable references in the loop and I can't because I borroed an immutable reference.
The problem is slightly different. what happens is that you can't walk this Rc<RefCell> tree, at least not interactively like this, because the "borrow" of such structures need to be keep while you are working with it. And your implementation releases the "borrow" after each loop.
But then if a borrow_mut() I get that value is a private field, so I'm
assuming I can't access any properties of the contained value if it is
a mutable reference?
Not really, what is happening here is that you are not calling the function RefCell::borrow_mut that returns a RefMut<Node>, you are in fact calling <Rc as BorrowMut>::borrow_mut that returns &mut RefMut<...>. And by accessing the value you are trying the access the private field value from RefCell, not Node.
Notice that in my implementation I explicitly called RefCell::borrow_mut, that fixes this issue.
Hopefully the title is accurate.
I would like to set a field on the Node struct that is inside of a vector. The node is a mutable reference, so I'm not sure why I can't assign to it. I'm guessing I am not properly unwrapping the Option?
Code example:
#[derive(Debug)]
enum ContentType {
Big,
Small,
}
#[derive(Debug)]
struct Node {
content_type: Option<ContentType>
}
#[derive(Debug)]
struct List {
nodes: Vec<Node>,
}
impl List {
fn get_node(&self, index: usize) -> Option<&Node> {
return self.nodes.get(index);
}
}
fn main() {
let list = List {
nodes: vec![Node {content_type: None}]
};
let node = &mut list.get_node(0);
println!("{:?}", list);
if let Some(x) = node {
x.content_type = Some(ContentType::Big)
}
}
Playground:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=18bdaf8b903d57dfbf49ebfb3252cf34
Receiving this error:
cannot assign to `x.content_type` which is behind a `&` reference
The error specifically refers to the return type of get_node, which is Option<&Node>. When you take the content out of the option here:
if let Some(x) = node {
x.content_type = Some(ContentType::Big)
}
x becomes &Node, which is not a mutable reference.
You need to change get_node to return a mutable reference.
impl List {
// Change to &mut self to borrow mutable items from self, and change the return type.
fn get_node(&mut self, index: usize) -> Option<&mut Node> {
return self.nodes.get_mut(index);
}
}
fn main() {
let mut list = List {
nodes: vec![Node {content_type: None}]
};
// Move this print statement above get_node(),
// as you can't get a non mutable reference while you are still holding onto a mutable reference
println!("{:?}", list);
let node = list.get_node(0);
if let Some(x) = node {
x.content_type = Some(ContentType::Big)
}
}
Playground
This means you can't get two mutable references to two different nodes at the same time however. See this question for a potential solution: How to get mutable references to two array elements at the same time?
It means what it says: get_node returns a Option<&Node> -- that's a non-mutable reference to a node. You can't mutate it.
Perhaps you meant to do
impl List {
fn get_node(&mut self, index: usize) -> Option<&mut Node> {
return self.nodes.get_mut(index);
}
}
Then you can do
let mut list = List {nodes: vec![Node {content_type: None}]};
let node = list.get_node(0);
if let Some(x) = node {
x.content_type = Some(ContentType::Big)
}
I'm just starting to learn Rust and I'm having some troubles understanding how ownership works in my case:
use std::ops::IndexMut;
// ================================================
struct Container {
root: Option<ContainerItem>,
items: Vec<ContainerItem>
}
impl Container {
pub fn create_item(&mut self) -> usize {
let item = create_test_item();
let idx = self.items.len();
self.items.push(item);
return idx;
}
pub fn get_item(&mut self, index: usize) -> &mut ContainerItem {
return self.items.index_mut(index);
}
pub fn new() -> Container {
let mut x = Container {
root: None,
items: Vec::new()
};
x.root = Some(create_test_item());
return x;
}
}
// ================================================
struct ContainerItem {
idx: usize,
children: Vec<usize>,
parent: usize,
has_parent: bool
}
impl ContainerItem {
pub fn add_child(&mut self, value: &mut ContainerItem) {
value.parent = self.idx;
value.has_parent = true;
self.children.push(value.idx);
}
}
// ================================================
fn create_test_item() -> ContainerItem {
ContainerItem {
idx: 1,
children: Vec::new(),
parent: 0,
has_parent: false
}
}
fn main() {
let mut container = Container::new();
let item_index = container.create_item();
let item = container.get_item(item_index);
if let Some(mut root) = container.root {
root.add_child(item);
}
}
I have a Container, with ContainerItems. Each ContainerItem can have children and also has a reference to its parent (both children and the parent are stored as their index in Container's items vec). This is all fine, adding items to the container works, but when I try to add a child to Container's root item (which is a ContainerItem), it throws errors:
error[E0503]: cannot use `container.root` because it was mutably borrowed
--> src/main.rs:68:12
|
66 | let item = container.get_item(item_index);
| --------- borrow of `container` occurs here
67 |
68 | if let Some(mut root) = container.root {
| ^^^^^^^^^^^^^^ use of borrowed `container`
69 | root.add_child(item);
| ---- borrow later used here
error[E0505]: cannot move out of `container.root.0` because it is borrowed
--> src/main.rs:68:17
|
66 | let item = container.get_item(item_index);
| --------- borrow of `container` occurs here
67 |
68 | if let Some(mut root) = container.root {
| ^^^^^^^^ move out of `container.root.0` occurs here
69 | root.add_child(item);
| ---- borrow later used here
If I change the call to add_child to use for e.g. create_test_item() as the argument, then it works fine.
I assume this might be because Container's items field has ownership over all ContainerItems? But I'm passing it by reference to add_child so I think this shouldn't matter, since I'm not changing the owner?
I think the trouble comes from the fact that in this Parent ←→ Child relation the items are sometimes referred to with references and sometimes with indices.
So, it is not always clear when the borrow should concern the container as a whole or just one item which is a part of it.
Moreover, the root item is not stored in the same place as the other items so no index can be used to refer to it.
I reorganised your code in order to always rely on indices (as far I understand your intention; maybe it is not always equivalent to what you wanted initially).
This way, as soon we have to adjust many indices, we just borrow the container as a whole.
Consequently, the add_child() method is moved from the item implementation to the container.
Note that the has_parent boolean was also a good opportunity to switch to Option.
Note also that, as long as we borrow an item with get_item() or get_item_mut(), we cannot create new items because the reallocation inside the Vec could invalidate the references; the borrow-checker will forbid that.
pub struct Container {
root: Option<usize>, // why not implicitly alway 0?
items: Vec<ContainerItem>,
}
impl Container {
pub fn create_item(&mut self) -> usize {
let idx = self.items.len();
let item = create_test_item(idx);
self.items.push(item);
idx
}
pub fn get_item(
&self,
index: usize,
) -> &ContainerItem {
&self.items[index]
}
pub fn get_item_mut(
&mut self,
index: usize,
) -> &mut ContainerItem {
&mut self.items[index]
}
pub fn new() -> Container {
let mut this = Container {
root: None,
items: Vec::new(),
};
this.root = Some(this.create_item());
this
}
pub fn add_child(
&mut self,
parent_idx: usize,
child_idx: usize,
) {
// forget child in previous parent if any
if let Some(prev_parent_idx) = self.items[child_idx].parent {
let prev_children = &mut self.items[prev_parent_idx].children;
let idx = prev_children.iter().position(|i| *i == child_idx);
prev_children.remove(idx.unwrap());
}
// give the child its new parent
let child = &mut self.items[child_idx];
child.parent = Some(parent_idx);
// append this new child to the parent
let parent = &mut self.items[parent_idx];
parent.children.push(child_idx);
}
}
#[derive(Debug)]
pub struct ContainerItem {
idx: usize,
children: Vec<usize>,
parent: Option<usize>,
}
fn create_test_item(idx: usize) -> ContainerItem {
ContainerItem {
idx,
children: Vec::new(),
parent: None,
}
}
fn main() {
let mut container = Container::new();
let item_idx = container.create_item();
println!("item: {:?}", container.get_item(item_idx));
if let Some(root_idx) = container.root {
println!("root: {:?}", container.get_item(root_idx));
println!("~~~~~~~~");
container.add_child(root_idx, item_idx);
println!("item: {:?}", container.get_item(item_idx));
println!("root: {:?}", container.get_item(root_idx));
}
}
let item = container.get_item(item_index);
if let Some(mut root) = container.root {
root.add_child(item);
}
container.get_item has already borrowed a value from &self. Therefore root.add_child will be restricted as long as that borrow exists.
Since the goal is simply to add an element to vec, there is no need to even have the attribute root: Option<ContainerItem>. By default when a new container is created, items can be an empty vector and when there is an item to be added it can be pushed to the vector.
Here is a simple way to implement the parent-child relationship
struct Parent<'a> {
children: &'a mut Vec<Child>,
}
impl Parent<'_> {
pub fn add(&mut self, c: Child) -> () {
let root = &mut self.children;
root.push(c)
}
pub fn get_item(
&self,
index: usize,
) -> &Child {
&self.children[index]
}
}
struct Child {
i: i32,
}
fn main() {
let c1 = Child { i: 1 };
let mut data = vec![c1];
let c12 = Child { i: 1 };
data.push(c12);
let mut p = Parent { children: &mut data };
let c12 = Child { i: 2 };
p.add(c12);
let item = p.get_item(2);
println!("{}", item.i) //2
Obviously other traits can be added to the parent
I have a struct Foo:
struct Foo {
v: String,
// Other data not important for the question
}
I want to handle a data stream and save the result into Vec<Foo> and also create an index for this Vec<Foo> on the field Foo::v.
I want to use a HashMap<&str, usize> for the index, where the keys will be &Foo::v and the value is the position in the Vec<Foo>, but I'm open to other suggestions.
I want to do the data stream handling as fast as possible, which requires not doing obvious things twice.
For example, I want to:
allocate a String only once per one data stream reading
not search the index twice, once to check that the key does not exist, once for inserting new key.
not increase the run time by using Rc or RefCell.
The borrow checker does not allow this code:
let mut l = Vec::<Foo>::new();
{
let mut hash = HashMap::<&str, usize>::new();
//here is loop in real code, like:
//let mut s: String;
//while get_s(&mut s) {
let s = "aaa".to_string();
let idx: usize = match hash.entry(&s) { //a
Occupied(ent) => {
*ent.get()
}
Vacant(ent) => {
l.push(Foo { v: s }); //b
ent.insert(l.len() - 1);
l.len() - 1
}
};
// do something with idx
}
There are multiple problems:
hash.entry borrows the key so s must have a "bigger" lifetime than hash
I want to move s at line (b), while I have a read-only reference at line (a)
So how should I implement this simple algorithm without an extra call to String::clone or calling HashMap::get after calling HashMap::insert?
In general, what you are trying to accomplish is unsafe and Rust is correctly preventing you from doing something you shouldn't. For a simple example why, consider a Vec<u8>. If the vector has one item and a capacity of one, adding another value to the vector will cause a re-allocation and copying of all the values in the vector, invalidating any references into the vector. This would cause all of your keys in your index to point to arbitrary memory addresses, thus leading to unsafe behavior. The compiler prevents that.
In this case, there's two extra pieces of information that the compiler is unaware of but the programmer isn't:
There's an extra indirection — String is heap-allocated, so moving the pointer to that heap allocation isn't really a problem.
The String will never be changed. If it were, then it might reallocate, invalidating the referred-to address. Using a Box<[str]> instead of a String would be a way to enforce this via the type system.
In cases like this, it is OK to use unsafe code, so long as you properly document why it's not unsafe.
use std::collections::HashMap;
#[derive(Debug)]
struct Player {
name: String,
}
fn main() {
let names = ["alice", "bob", "clarice", "danny", "eustice", "frank"];
let mut players = Vec::new();
let mut index = HashMap::new();
for &name in &names {
let player = Player { name: name.into() };
let idx = players.len();
// I copied this code from Stack Overflow without reading the prose
// that describes why this unsafe block is actually safe
let stable_name: &str = unsafe { &*(player.name.as_str() as *const str) };
players.push(player);
index.insert(idx, stable_name);
}
for (k, v) in &index {
println!("{:?} -> {:?}", k, v);
}
for v in &players {
println!("{:?}", v);
}
}
However, my guess is that you don't want this code in your main method but want to return it from some function. That will be a problem, as you will quickly run into Why can't I store a value and a reference to that value in the same struct?.
Honestly, there's styles of code that don't fit well within Rust's limitations. If you run into these, you could:
decide that Rust isn't a good fit for you or your problem.
use unsafe code, preferably thoroughly tested and only exposing a safe API.
investigate alternate representations.
For example, I'd probably rewrite the code to have the index be the primary owner of the key:
use std::collections::BTreeMap;
#[derive(Debug)]
struct Player<'a> {
name: &'a str,
data: &'a PlayerData,
}
#[derive(Debug)]
struct PlayerData {
hit_points: u8,
}
#[derive(Debug)]
struct Players(BTreeMap<String, PlayerData>);
impl Players {
fn new<I>(iter: I) -> Self
where
I: IntoIterator,
I::Item: Into<String>,
{
let players = iter
.into_iter()
.map(|name| (name.into(), PlayerData { hit_points: 100 }))
.collect();
Players(players)
}
fn get<'a>(&'a self, name: &'a str) -> Option<Player<'a>> {
self.0.get(name).map(|data| Player { name, data })
}
}
fn main() {
let names = ["alice", "bob", "clarice", "danny", "eustice", "frank"];
let players = Players::new(names.iter().copied());
for (k, v) in &players.0 {
println!("{:?} -> {:?}", k, v);
}
println!("{:?}", players.get("eustice"));
}
Alternatively, as shown in What's the idiomatic way to make a lookup table which uses field of the item as the key?, you could wrap your type and store it in a set container instead:
use std::collections::BTreeSet;
#[derive(Debug, PartialEq, Eq)]
struct Player {
name: String,
hit_points: u8,
}
#[derive(Debug, Eq)]
struct PlayerByName(Player);
impl PlayerByName {
fn key(&self) -> &str {
&self.0.name
}
}
impl PartialOrd for PlayerByName {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for PlayerByName {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.key().cmp(&other.key())
}
}
impl PartialEq for PlayerByName {
fn eq(&self, other: &Self) -> bool {
self.key() == other.key()
}
}
impl std::borrow::Borrow<str> for PlayerByName {
fn borrow(&self) -> &str {
self.key()
}
}
#[derive(Debug)]
struct Players(BTreeSet<PlayerByName>);
impl Players {
fn new<I>(iter: I) -> Self
where
I: IntoIterator,
I::Item: Into<String>,
{
let players = iter
.into_iter()
.map(|name| {
PlayerByName(Player {
name: name.into(),
hit_points: 100,
})
})
.collect();
Players(players)
}
fn get(&self, name: &str) -> Option<&Player> {
self.0.get(name).map(|pbn| &pbn.0)
}
}
fn main() {
let names = ["alice", "bob", "clarice", "danny", "eustice", "frank"];
let players = Players::new(names.iter().copied());
for player in &players.0 {
println!("{:?}", player.0);
}
println!("{:?}", players.get("eustice"));
}
not increase the run time by using Rc or RefCell
Guessing about performance characteristics without performing profiling is never a good idea. I honestly don't believe that there'd be a noticeable performance loss from incrementing an integer when a value is cloned or dropped. If the problem required both an index and a vector, then I would reach for some kind of shared ownership.
not increase the run time by using Rc or RefCell.
#Shepmaster already demonstrated accomplishing this using unsafe, once you have I would encourage you to check how much Rc actually would cost you. Here is a full version with Rc:
use std::{
collections::{hash_map::Entry, HashMap},
rc::Rc,
};
#[derive(Debug)]
struct Foo {
v: Rc<str>,
}
#[derive(Debug)]
struct Collection {
vec: Vec<Foo>,
index: HashMap<Rc<str>, usize>,
}
impl Foo {
fn new(s: &str) -> Foo {
Foo {
v: s.into(),
}
}
}
impl Collection {
fn new() -> Collection {
Collection {
vec: Vec::new(),
index: HashMap::new(),
}
}
fn insert(&mut self, foo: Foo) {
match self.index.entry(foo.v.clone()) {
Entry::Occupied(o) => panic!(
"Duplicate entry for: {}, {:?} inserted before {:?}",
foo.v,
o.get(),
foo
),
Entry::Vacant(v) => v.insert(self.vec.len()),
};
self.vec.push(foo)
}
}
fn main() {
let mut collection = Collection::new();
for foo in vec![Foo::new("Hello"), Foo::new("World"), Foo::new("Go!")] {
collection.insert(foo)
}
println!("{:?}", collection);
}
The error is:
error: `s` does not live long enough
--> <anon>:27:5
|
16 | let idx: usize = match hash.entry(&s) { //a
| - borrow occurs here
...
27 | }
| ^ `s` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
The note: at the end is where the answer is.
s must outlive hash because you are using &s as a key in the HashMap. This reference will become invalid when s is dropped. But, as the note says, hash will be dropped after s. A quick fix is to swap the order of their declarations:
let s = "aaa".to_string();
let mut hash = HashMap::<&str, usize>::new();
But now you have another problem:
error[E0505]: cannot move out of `s` because it is borrowed
--> <anon>:22:33
|
17 | let idx: usize = match hash.entry(&s) { //a
| - borrow of `s` occurs here
...
22 | l.push(Foo { v: s }); //b
| ^ move out of `s` occurs here
This one is more obvious. s is borrowed by the Entry, which will live to the end of the block. Cloning s will fix that:
l.push(Foo { v: s.clone() }); //b
I only want to allocate s only once, not cloning it
But the type of Foo.v is String, so it will own its own copy of the str anyway. Just that type means you have to copy the s.
You can replace it with a &str instead which will allow it to stay as a reference into s:
struct Foo<'a> {
v: &'a str,
}
pub fn main() {
// s now lives longer than l
let s = "aaa".to_string();
let mut l = Vec::<Foo>::new();
{
let mut hash = HashMap::<&str, usize>::new();
let idx: usize = match hash.entry(&s) {
Occupied(ent) => {
*ent.get()
}
Vacant(ent) => {
l.push(Foo { v: &s });
ent.insert(l.len() - 1);
l.len() - 1
}
};
}
}
Note that, previously I had to move the declaration of s to before hash, so that it would outlive it. But now, l holds a reference to s, so it has to be declared even earlier, so that it outlives l.
I have a function that returns a flat-mapped Vec over children of a tree:
use std::iter;
#[derive(Clone)]
struct Tree {
value: String,
children: Vec<Tree>,
}
struct NoClone;
impl NoClone {
pub fn children(&self, from: &Tree) -> Vec<Tree> {
from.children.clone()
}
pub fn descendants_vec<'a>(&'a self, from: Tree) -> Vec<Tree> {
let children = self.children(&from);
iter::once(from)
.chain(children.into_iter().flat_map(|child| self.descendants_vec(child)))
.collect::<Vec<Tree>>()
}
pub fn descendants_iter<'a>(&'a self, from: Tree) -> Box<Iterator<Item = Tree> + 'a> {
let children = self.children(&from);
Box::new(iter::once(from)
.chain(children.into_iter().flat_map(move |child| {
self.descendants_iter(child)
})))
}
}
fn main() {
//println!("Flattened (Iter): {:?}", mapped_iter());
println!("Flattened (Vec): {:?}", mapped_vec());
}
fn tree() -> Tree {
let tree_a = Tree {
value: "a".to_owned(),
children: Vec::new(),
};
let tree_b = Tree {
value: "b".to_owned(),
children: Vec::new(),
};
let tree_c = Tree {
value: "c".to_owned(),
children: Vec::new(),
};
Tree {
value: "abc".to_owned(),
children: vec![tree_a, tree_b, tree_c],
}
}
/*fn mapped_iter() -> Vec<String> {
let tree = tree();
let no_clone = NoClone;
no_clone.descendants_iter(tree).map(|x| x.value).collect::<Vec<String>>()
}*/
fn mapped_vec() -> Vec<String> {
let tree = tree();
let no_clone = NoClone;
no_clone.descendants_vec(tree)
.into_iter()
.map(|x| x.value)
.collect::<Vec<String>>()
}
I would like to avoid the intermediate collect/iter and use descendants_iter which returns an Iterator (boxed until we get impl traits).
However, uncommenting the blocks calling this function causes the compiler to complain with the following error:
error: `no_clone` does not live long enough
--> <anon>:63:1
|
62 | no_clone.descendants_iter(tree).map(|x| x.value).collect::<Vec<String>>()
| -------- borrow occurs here
63 | }
| ^ `no_clone` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
error: aborting due to previous error
Any ideas about how to use the descendants_iter function?