Home > Back-end >  cannot borrow `args` as mutable because it is also borrowed as immutable
cannot borrow `args` as mutable because it is also borrowed as immutable

Time:08-09

let mut args: Vec<String> = args().collect();
for mut i in 0..args.len() {
  if args[i].contains("-type") {
    project_type = args[i].split("=").last().unwrap();
    args.remove(i);
    i-=1;
  }
}

I'm very new to rust and want to know why this code gives me the error "cannot borrow 'args' as mutable because it is also borrowed as immutable" and how i can fix it

I'm trying to check if the args Vec contains an item like "-type=some_type", then put "some_type" in a variable called "project_type". Finally I want to remove the item "-type=some_type" from the list and keep searching.

edit: if I'm doing what I'm trying to do wrong, i would appreciate a better solution.

CodePudding user response:

str::split doesn't create new string objects, it returns references to the existing one. So your project_type variable is a reference to a string in args. When you remove from args, you invalidate all of those references.

You can convert a &str to a String and break the reference with .to_owned()

project_type = args[i].split("=").last().unwrap().to_owned();

Now, for loops in Rust iterate over data structures. As such, your i -= 1 trick won't work. i will just get reset back to where it was at the next iteration. If you want to do this the way you're currently doing it, you want a while loop.

let mut i = 0
while i < args.len() {
  if ... {
    ...
  } else {
    i  = 1;
  }
}

However, let's think about this a bit more functionally. What it sounds like you want is to find a matching element of a vector (and its index) and then do something with it. So let's break that down into two separate problems.

We use enumerate to get a collection together with its index, and find to search it. Since it looks like you expect the value to be there, we'll unwrap it and panic if it's not there. If you want to handle the error, convert this to a match.

let (idx, element) = args.iter().find(|x| x.contains("-type")).unwrap();

Once we have it, we can do our work on element to get the project type.

project_type = element.split("=").last().unwrap().to_owned();

Note that at this point project_type does not depend on args at all. element does, and Rust may be smart enough to see this, but let's just be perfectly safe and make sure element gets dropped before we modify args. Once there are no more references to args, we can mutably borrow to do the remove operation.

let idx = {
  let (idx, element) = args.iter().enumerate().find(|(_, x)| x.contains("-type")).unwrap();
  project_type = element.split("=").last().unwrap().to_owned();
  idx
}
args.remove(idx);
  • Related