1

I can't understand why I am getting this error below: `

error[E0502]: cannot borrow `*s` as mutable because it is also borrowed as immutable
 --> src/main.rs:8:5
  |
7 |     let char_h = s.get(0..0).unwrap().clone();
  |                  ----------- immutable borrow occurs here
8 |     s.replace_range(0..0, "h");
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
9 |     println!("char before {char_h} string after {}", s);
  |                            ------ immutable borrow later used here

For more information about this error, try `rustc --explain E0502`.
error: could not compile `q_line_out_of_scope` due to previous error

In the code:

fn main() {
    let mut s = String::from("Hello World!!");
    try_changes(&mut s);
}

fn try_changes(s: &mut String) {
    let char_h = s.get(0..0).unwrap().clone();
    s.replace_range(0..0, "h");
    println!("char before {char_h} string after {}", s);
}

`

I understand that I borrowed the 's' in line 7 'unwrap', but after borrow it I used clone and have no more references to the borrowed value 's'. So I would like to know why rust don't "drop" the borrow in this case, and a solution on how I could perform this feature (modify a string and have the old string version in some variable). Thanks.

I have tried to use 'as_ref' but things are becoming more complex and I think I am missing something, so I am trying to understand that so I can procced with rust studying.

Yuri Theo
  • 13
  • 2
  • 1
    `char_h` is a `&str`. You want `let char_h = s.get(0..0).unwrap().to_string();` to make a `String` from the sliced `&str`. – kotatsuyaki Dec 11 '22 at 02:19
  • @kotatsuyaki Since `char_h` is only used to print out, it is more ideomatic to get `char_h` as a character instead of a `String` with `s.chars().nth(0).unwrap();`. – Kaplan Dec 11 '22 at 15:28
  • @Kaplan Right, I didn't notice that the intention was to get a single character instead of a slice. – kotatsuyaki Dec 11 '22 at 15:52

1 Answers1

1

First, you probably want 0..1 instead of 0..0. In Rust, and most other programming languages, range definitions are inclusive on the lower end and exclusive on the upper end.

Next, s.get(0.11).unwrap() will be of type &str, i.e., a string slice. Cloning that will just copy the reference. See here: What happens when you clone a `&str`?

And because of that, cloning won't "release" the borrow. Instead, you'll need to create a new, owned string, which would be done via to_string().

See here: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=9ad9ccf4c23669a77b84c1615501afde

fn main() {
    let mut s = String::from("Hello World!!");
    try_changes(&mut s);
}

fn try_changes(s: &mut String) {
    let char_h = s.get(0..1).unwrap().to_string();
    s.replace_range(0..1, "h");
    println!("char before {} string after {}", char_h, s);
}
cadolphs
  • 9,014
  • 1
  • 24
  • 41