ste_kwr
ste_kwr

Reputation: 1010

Cannot borrow as mutable when running next on an immutable iterator (no other borrows)

When trying to run the following code:

fn main() {
    let s1 = String::from("hello world");
    println!("The first word in the string is: {}", return_first_word(&s1));
}

fn return_first_word(s: &String) -> String {
    let t = s.split(" ");
    String::from(t.next().unwrap())
}

I get the error cannot borrow as mutable on the line String::from(t.next().unwrap()). Naturally, when I replace the line let t = ... with let mut t = ... the code works perfectly.

My question is, can someone explain why? What is being borrowed here, and by what? I checked the type of my newly created immutable variable t and it is an iterator. Why would it be an issue iterating over an iterator??

Upvotes: 4

Views: 1260

Answers (1)

Silvio Mayolo
Silvio Mayolo

Reputation: 70257

If you're familiar with a language like Java, you might expect str::split to return an array, but it actually doesn't. In Rust, str::split returns an iterator. It doesn't actually split the entire string immediately; it gives you a special iterator object that does it as you iterate over the string.

Now, iteration is a stateful process in Rust. To iterate over something, you call Iterator::next, which changes the iterator's internal state and produces the next value. If called repeatedly, it gives you every value of the iterator in order and then starts producing None. Since next changes the state of the iterator, it must have a mutable reference to the iterator.

When you declare a variable with let in Rust, it's immutable. You can't change it. You've told the Rust system you have no intention of changing it. So Rust complains when you try to take a mutable reference to a thing (in your case, an iterator) that you promised to never change. Instead, you need to use let mut to indicate your intentions.

Upvotes: 10

Related Questions