Reputation: 446
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));
.
String
from &String
?&String
with *
errors? I understood *&
dereferencing to returns just the value of the reference.Upvotes: 1
Views: 4275
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
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