Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optionally push item to Vec or return existing item [duplicate]

Tags:

rust

I have a function that will either return a reference to existing item from a Vec, or push a new item onto the Vec and return a reference to that existing item. I created a basic exmple that illustrates what I want to do:

struct F {
    x: Vec<Vec<String>>,
}

impl F {
    fn foo(&mut self, s: String) -> &[String] {
        for strings in &self.x {
            if strings.contains(&s) {
                return &strings;
            }
        }

        self.x.push(vec![s]);

        &self.x[self.x.len() - 1]
    }
}

But when I try to compile this, I get an error about lifetimes:

error[E0502]: cannot borrow `self.x` as mutable because it is also borrowed as immutable
  --> src/lib.rs:13:9
   |
6  |     fn foo(&mut self, s: String) -> &[String] {
   |            - let's call the lifetime of this reference `'1`
7  |         for strings in &self.x {
   |                        ------- immutable borrow occurs here
8  |             if strings.contains(&s) {
9  |                 return &strings;
   |                        -------- returning this value requires that `self.x` is borrowed for `'1`
...
13 |         self.x.push(vec![s]);
   |         ^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here

I don't understand this error, because in my mind the immutable borrow on line 7 is guaranteed to no longer exist by line 13, since the function will either have returned before line 13, or the for loop will have ended, and the borrow should end with it. What am I missing?

like image 960
Lily Mara Avatar asked Oct 29 '25 17:10

Lily Mara


1 Answers

I think this is a limitation of current borrow checker, you can do this instead:

struct F {
    x: Vec<Vec<String>>,
}

impl F {
    fn foo(&mut self, s: String) -> &[String] {
        let ret = self.x.iter().position(|strings| strings.contains(&s));

        if let Some(ret) = ret {
            &self.x[ret]
        } else {
            self.x.push(vec![s]);
            &self.x.last().unwrap()
        }
    }
}
like image 191
Stargateur Avatar answered Oct 31 '25 13:10

Stargateur



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!