References and Copy Trait in Rust.

vikram fugro
3 min readMay 6, 2018

--

Here, we will cover a very simple and basic topic in Rust. The relation between reference (&) and Copy trait.

What happens above is that struct Cat is passed to thetest function. This compiles fine. Now let’s what happens if I add one more call to the functiontest:

error[E0382]: use of moved value: `c`
--> src/main.rs:11:10
|
10 | test (c);
| - value moved here
11 | test (c);
| ^ value used here after move
|
= note: move occurs because `c` has type `Cat`, which does not implement the `Copy` trait

The error is pretty simple, telling you that you cannot use a moved variable, since Cat does not have the Copy trait, as evident from the Cat’s definition. The value got moved in the first call to the function test. Note that instead of using a function, the same can also be demonstrated like this:

let c = Cat{ name: String::from("meow") };
let d = c;
let e = c;

This code will complain about the same thing at assignment to e for using a moved variable c. c got moved into d before assigning it to e.

Ok! back to using function. Now, let’s make T a Copy type. But why? Because Cat got moved. Ok… so? So it means it can’t be copied and to quickly prove that, let’s make T as a receiver for theCopy type.

fn test <T> (t:T) where T:Copy {
}

… and the code fails to compile with the following error.

error[E0277]: the trait bound `Cat: std::marker::Copy` is not satisfied
--> src/main.rs:10:4
|
10 | test (c);
| ^^^^ the trait `std::marker::Copy` is not implemented for `Cat`
|
note: required by `test`
--> src/main.rs:5:1
|
5 | fn test <T> (t:T) where T:Copy {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

But this time, right at the first call to the functiontest! The previous one had detected the issue at the second call. Unlike the previous one, over here there is an argument mismatch as Cat does not have theCopy trait whereas the function test, now only accepts the Copy types.

Now, lets switch back to the older definition of function test and instead pass a & type to test.

The compilation succeeds. Also, multiple calls to the function test do not irk the compiler. We can demonstrate the same concept like this:

let c = Cat{ name: String::from("meow") };
let d = &c;
let e = d;
let f = &c;

This was pretty straight forward and it’s obvious that this _has_to_ work because there are references being passed around and not values. Basically, there are multiple immutable references being taken. Pretty simple!

All done, now we can take a step back and realise that the reason it works is because the & type in Rust derives the Copy trait . Let’s again make T a Copy type.

fn test <T> (t:T) where T:Copy {
}

… and the code compiles this time. So in a nutshell, the & type is just like any other primitive type for eg. integer i32 in this regard. It silently derives the Copy trait. This is built-in and is a part of prelude. Prelude is “the list of things that Rust automatically imports into every Rust program”.

So how do we pass copies of Cat around, so that the original variable can be used further? or is it even allowed for Cat over here to be a Copy type in first place? For that we will have to look into things like derive mechanism in Rust and Copy's sibling called Clone. Topic for another discussion!

--

--

vikram fugro
vikram fugro

Written by vikram fugro

Open Source Software Enthusiast, Polyglot & Systems Generalist.

No responses yet