Rust mutable String declaration from String reference argument

I have

fn main() {
    let x = String::from("12");
    fun1(&x);
}
fn fun1(in_fun: &String) {
    let mut y = _______;
    y.push_str("z");
    println!("in fun {}", y);
}

where _____ is the code for declaring y based on the argument in_fun.

At first I tried let mut y = *in_fun; which errors move occurs because '*in_fun' has type 'String', which does not implement the 'Copy' trait and also let mut y = String::from(*in_fun); which gives same error.

The thing that worked was let mut y = String::from(format!("{}", *in_fun));.

  1. Is this the right way to declare a mutable String from &String?
  2. Also I still don't understand why dereferencing &String with * errors? I understood *& dereferencing to returns just the value of the reference.

Upvotes: 1

Views: 4275

Answers (2)

Aplet123
Aplet123

Reputation: 35560

First of all, the working code:

fn fun1(in_fun: &String) {
    let mut y = in_fun.clone();
    y.push_str("z");
    println!("in fun {}", y);
}

Or, your instincts tell you you have to dereference, so (*in_fun).clone() works just the same, but is a bit redundant. *in_fun.clone() does NOT work because it's equivalent to *(in_fun.clone()) (dereferencing the clone), which isn't what you want. The reason you don't need to dereference the reference before calling clone is because Rust's method resolution allows you to call methods of a type or access properties of a type using a reference to the type, and .clone has an &self receiver.

The reason that let mut y = *in_fun doesn't work is because this attempts to move the string out from underneath the reference, which doesn't work.

Upvotes: 3

Robert Cutajar
Robert Cutajar

Reputation: 3731

&String is an immutable reference. Rust is strict about this and prevents many common mishaps we people tend to run into. Dereferencing &String is not possible as it would break the guarantees of safety in rust, allowing you to modify where you only have read access. See the ownership explanation.

The function should either accept a mutable reference &mut String (then the string can be modified in place) or it needs to .clone() the string from the immutable reference.

Taking a mutable reference is more efficient than cloning, but it restricts the caller from sharing it immutably in parallel.

If the only thing you want to achieve is to print out some additional information, the best way I know of is:

fn fun1<S: std::fmt::Display>(in_fun: S) {
    println!("in fun {}z", in_fun);
}

fn main() {
    let mut x = String::from("12");
    fun1(&x);
    fun1(&mut x);
    fun1(x);
    fun1("12");
}

I use a Display trait so anything that implements will do. See the playground.

On the other hand, if you really need an owned string, then ask for it :)

fn fun1<S: Into<String>>(in_fun: S) {
    let mut y = in_fun.into();
    y.push('z');
    println!("in fun {}", y);
}

fn main() {
    let x = String::from("12");
    fun1(&x);
    fun1(x);
    fun1("12");
}

This way you can accept both &str and String and keep efficient, avoiding cloning if possible.

Upvotes: 3

Related Questions