Copy vs Borrow Trait, need a basic explaination

Hey Everyone, Brand new to Rust, just started this week, I am posting just to get some basic understanding of borrow versus copy and trying to get used to using this community.

Here is my problem, I wrote a function to produce the value of the data type as a string, I also take user input into a mutable variable of string type. I try to read the value of the string variable into the function, and it used to give me the data type of the string, but after I change the mutable variable from a string type to a f64, when I try to pass the string variable to the function to read the data type it gives me a error that string doesn't have copy trait, does that mean that the only way I would be able to get the data type would be to clone the string and send it too the function?

Here is the main function body of the code with the input from the user of the string and the call to the data type function:

let mut user_input_float = String::new();

    io::stdin()
        .read_line(&mut user_input_float)
        .expect("Failed to read line");

    println!("You entered: {}", user_input_float);
    println!("Type of what you entered: {}", type_of(user_input_float));

    let user_input_float: f64 = user_input_float.trim().parse().expect("Please type a number!");

    println!("Your input float after parsing: {}", user_input_float);
    println!("Your input float data type after parsing: {}", type_of(user_input_float));

Here is the functio:

fn type_of<T>(_: T) ->&'static str {
    type_name::<T>()
    //:: <T> is an associated function of type_name that acts on
    //Type_name
}

I'm also a little confused by the function, is a empty data type, then the variable reference I pass it copied to T, which type_name then acts on? I copied this code from somewhere else in this forum so if someone would explain how the purpose is that would be great too.

Here is my compiler error message:

   |
31 | ...et mut user_input_float = String::new();
   |       -------------------- move occurs because `user_input_float` has type `String`, which does not implement the `Copy` trait
...
38 | ...rintln!("Type of what you entered: {}", type_of(user_input_float));
   |                                                    ---------------- value moved here
39 | ...
40 | ...et user_input_float: f64 = user_input_float.trim().parse().expect("Pl...
   |                               ^^^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
   |
   = note: borrow occurs due to deref coercion to `str`

This code is really just to learn the language and get some basic practice, if any one wants to take some time to explain these concepts to a newbie I would greatly appreciate it, and send good coding karma your way. Really looking to learn from you guys and be part of the Rust community :smile:

Hi, welcome! Make sure to read through the 4th chapter of the Rust book for an explanation of Rust’s ownership model.

Understanding Ownership - The Rust Programming Language

Your type_of function takes ownership of the argument you pass to it. This means that the value you pass it cannot be used anymore after the call to type_of in the calling function; you’ve given away ownership, and it’s gone. Except when the type is Copy, then it’s not as bad, because – well – it can be cheaply and implicitly copied; but cloning a String is expensive, and a generic type T can be an expensive-to-clone type, so better not take ownership when we don’t need to…

fn type_of<T>(_: &T) ->&'static str {
    type_name::<T>()
}

Now you can make type_of borrow the value instead, and change the call-site to type_of(&user_input_float).

As a rule of thumb, everytime you write user_input_float in an expression without a preceding &, it is moved, with two exceptions:

  • in a method call the receiver type can be borrowed implicitly, as in user_input_float.trim(), where trim is a &self method
  • in certain macros, particularly the println! macro, the call to println!("You entered: {}", user_input_float) does not take ownership of user_input_float. That’s a (syntactically slightly confusing) quirk of how println! (and other macros with formatting) work; basically they operate by taking a reference for you implicitly, they literally expand to something that uses your expression preceded by a “&” (you can take a look at macro expansions e.g. in the playground under “Tools”->“Expand macros”)
    • note that in the println!("Type of what you entered: {}", type_of(user_input_float)) call however, it’s only the result of type_of(user_input_float) that’s not moved in order to be printed; the function argument of type_of is still moved, which was the main problem in your code
4 Likes

You covered it right with type_of. Thanks for that! I had a brain fart heh

Thanks @steffahn for responding! Makes sense, its a lot like c/c++ where you can pass the function a pointer to the variable instead of the variable itself and it is a lot less data intensive, only with Rust when you copy a variable, rust moves ownership from the first variable to the second. I have been reading chapter 4 of the book today and understanding it, what tripped me up was that I didn't know that calling a function with a variable passed the whole variable to the function and changes scope and ownership of the value, I will make sure to pass by reference to my functions from now on. Thanks @steffahn

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.