String replace_range

Is this the best way to replace the value of a String with a new value?

fn main() {
  let mut s = String::from("first");
  println!("s = {}", s);
  s.replace_range(.., "second");
  println!("s = {}", s);
}

(Playground)

If you want to repalce the whole string, s = "second".to_string() would be the shortest code. If you want to re-use the storage, then s.clear(); s.push_str("second") would work.

Does s.replace_range(.., "second"); also reuse the storage?

It looks like it uses Vec::splice internally. That, in turn, uses Vec::extend when there is nothing kept beyond the replaced range (i.e. the range includes the last source element). extend uses the existing allocation if possible, and will do at most a single allocation in your case, as the length of "second" is known without exhausting the iterator.

In short, yes, replace_range reuses the storage.

1 Like

Interesting. I'm new enough to Rust that I don't know where to look to find the implementation of a built-in method. Where did you find that?

When you look at the docs, like for replace_range, there's a [src] link on the right. It's not easy to navigate to other stuff from there, but you could see that it calls splice, go back to look that up and see its [src], and so on.

2 Likes

Of course, to reuse the memory, there's also the oft-forgotten clone_from.

fn main() {
    let mut s1 = String::from("first");
    let s2 = String::from("second");
    println!("s2 = {}", s1);
    s1.clone_from(&s2);
    println!("s2 = {}", s1);
}

Unfortunately it only works with a &String and not a &str.

1 Like

You can use ToOwned::clone_into once that lands instead of Clone::clone_from

2 Likes