- Some simple types in Rust support copy semantics,
rather than move semantics, as we know.
So for example, numbers,
there's a structure called SystemTime.
The option enum.
When you assign one of these to another one,
it does a bitwise copy, okay?
It is always a bitwise copy
for types which implement the copy mechanism.
So in a nutshell, as we're going to see in a moment,
there is a trait called copy
which you can implement yourself
if you want your types to also support copy semantics.
So in this example here,
I've started off Num1 is a 32 bit integer.
So i32, one of these kind of primitive types,
implements the copy trait.
So Num1 is 42.
So for types like integers,
which implement the copy trait,
when you assign a variable to another,
it does a bitwise copy.
It doesn't kind of move ownership
or anything hideous or insidious.
It just does a straightforward bit copy
from Num1 into Num2.
So Num2 becomes a bitwise copy like so,
and Num1 and Num2 are completely independent of each other.
They kind of exist side by side.
It just copied the bits from Num1 into Num2.
They're separate variables, obviously.
So I could change Num2,
I could increment Num2.
So Num2 was 42,
it becomes 43.
And then when I output Num1, it's 42.
When I open Num2, it's 43.
So for built-in types,
or for some simple types like i32 an option,
it does copying out of the box.
In other words, those types implement the copy trait.
So if you want to support copy semantics in your structures
so that your structure here is more like a value type
as you'd call it in C#.
What you do is you implement the copy trait
and the copy trait is what we call a marker trait.
It doesn't have any methods,
it's just like a stamp
like a Boolean flag on that data type.
It tells the compiler,
this type supports the concept of copying.
So if you assign A to B,
do a bitwise copy
rather than doing a move.
Now copy inherits from clone.
So if one of your structures implements the copy trait,
it must also implement the super trait clone.
So it looks like this,
the clone trait,
we looked at this in the previous demo,
it has a clone method
that you can implement
plus a clone from method
that you typically don't implement.
It's already kind of implemented
with a default behavior.
So cloning is where you basically do a carbon copy
of an object.
The copy trait inherits from clone.
So a structure of yours which implements copy
must also implement clone.
So you can find your structure type here.
I've got a structure type called currency
and the currency will implement the copy trait
but there aren't any methods there to implement.
It's just a flag really
telling the compiler implement copy semantics for this type,
not move semantics.
Don't move the data away on an assignment
just do a bitwise copy.
That's what you're saying, right?
But if you implement the copy trait
then also you have to implement the clone trait
because that's what inheritance means in Rust.
If you implement a trait
you must also implement all of the methods above.
So currency would have to implement the clone method
and the clone from,
or to be more precise
it would implement the clone method
and it would probably inherit the default implementation
of clone from
because you typically don't need to override that.
It already has a sufficient implementation already.
So currency implements copy,
and it also implements clone.
Here is an example.
I've done this manually initially.
Here's my Currency structure dollars and cents.
Okay so interestingly
that the individual fields here support copying
but the structure itself doesn't natively support copying
unless you actually tell the compiler so.
So unless and until you implement the copy trait
for currency
when you do that,
it means that currency assignment
will be a bitwise copy rather than a move.
So that means if you said currency one was $10.50
and then you had currency two,
when you say currency two equals currency one
it'll do a bitwise copy of the values in here
10.50 like that,
rather than moving the data from C1
it'll just do a bitwise copy like so, okay?
So you just have to implement the copy trait.
There are no methods,
it's just like a statement of intent
but you do have to implement the super trait as well.
So if you implement copy for currency
you must also implement clone.
And in here it's interesting,
the clone method
it says custom cloning,
it just returns.
Remember the point of the clone method
is to basically create an object that has the same data.
So if I said if C1 contain the values 10.50
and I said C2 equals C1.clone
if I did that, okay?
Then it'll call the clone method.
And the clone method does some printing maybe
and then it returns the contents of itself.
Remember the self reference
is a reference to the object
upon which you call the clone method.
When you say C1.clone self will be C1.
So what you do is you return the contents
of that reference
it'll return the contents of this object,
will be returned.
So C1.clone will return
a copy of 10.50 like so
and C2 becomes that, okay?
So that's how it works.
So in this syntax here,
we can think of references
as being a little bit like pointers.
If ever pointed to an object,
then star returns the contents of that object,
it returns a copy of C1
and that's what would then get assigned
into the variable on the left hand side
of the assignment, right?
Okay so this is how to implement the copy trait
and the clone trait manually.
But often you can rely on default implementation.
You can just ask a compiler
to automatically implement the copy trait
and the clone trait, okay?
And you can do that
if every field and your structure implements copy.
So this field here implements the copy trait
integers know how to copy themselves.
A bitwise copy i32 does implement copy.
If all the fields inside the structure
implement the copy trait
then you can ask the compiler
to automatically generate a copy implementation
and automatically implement the clone implementation.
So you don't have to write any implementation yourself
it'll be generated for you.
The default copy will be bitwise.
So if you said C1 equals C2,
it'll do a bitwise copy of each field
and give you back the resulting object.
And in a similar way
the default cloning is also field by field, okay?
So if you said C1 equals C2.clone,
then the clone implementation,
it'll call the clone method on that
and the clone method on that, okay?
And for most types, this is sufficient.
It's just a matter of expressing the fact that you want it.
You want your structure type to support copying
and therefore cloning as well,
because this trait inherits from there.
So if you implement that trait,
you've also got to specify
that you implement that trait as well.
So I feel an example coming on,
lesson 12 traits is the project,
we'll kick off with the main code.
The structure we're going to look at
is in the copyable module.
That's where we're going to have our structure.
And the code that's going to use that structure
is going to be in demo_copyable.rs
and then we'll run the project once we've discussed.
Okay, so then here's main,
in main let me un-comment demo copyable.
This is the last demo of the lesson.
It's been quite a journey.
So let's un-comment that statement.
And then in the structures
I want to look at the example
that illustrates copyable.
Okay, so I have a currency structure
with a dollars and cents
and I've asked the compiler
to automatically generate the debug output.
Remember the default debug
will output the name of the structure currency
and it'll output the dollars
and the cents field one by one.
I've also requested automatic implementation
of the copy trait,
which will do a bitwise copy of each field
effectively to give me back
a bitwise copy of the composite.
And I've asked for it to implement the clone
so it'll clone that field
and clone that field as well.
I've got a new method kind of usual
really a new associated function I should say,
which creates and returns a currency object
with the values that I specify.
Down here, I've got the manual implementation
of copy and clone.
Those are commented out.
We'll come back and un-comment those later
in a few minutes.
First of all,
let's just run with the structure as it stands
with its default trade implementation.
Let's see how that looks.
So demo copyable,
I create a currency $10.99
and then I assign C1 to C2.
At this point,
the compiler will say does it have to do a copy
or does it do a move?
It depends on whether currency implements copy.
Well, currency does implement copy.
We did request that.
Therefore this will be a copy.
It'll do a bitwise copy of each field,
dollars and cents into here.
So C2 will be a copy of $10.99,
no movement has occurred.
We haven't moved data out of C1 into C2
like what would happen with other types
that don't implement copy.
It's just done a bitwise copy
from that data into that object.
So I can continue to use C1 and C2.
I can change C1 to be $11.
It was 10.
I can change C2 to be $22.
That was also 10 initially.
And then I can output using the debug formatter
which is quite cool.
I can output C1
that would be $11.99
and C2 will be $22.99,
$22,99, right?
So let's just run this to confirm.
So using the debug formatter
the currency one $11 99.
That's correct, isn't it, $11.99?
And C2,
again, using the debug formatter
using the debug formatter here,
it outputs all the fields.
C2 is $22 99.
Okay so that's correct.
That's using the the default implementation
of the copy trait.
So what I could do
is I could rather than relying
on the default implementation
I could rely on custom implementation.
I could implement the copy trait,
a market trait you just say as a statement of fact
I want copy behavior,
not move behavior,
and then a custom implementation of clone as well
which just basically returns
a copy of my own data effectively,
the contents of,
so this will be custom behavior
that's going to be implemented achieved.
So let's do a cargo run again.
Okay, so currency, those values,
the default copying did work.
I haven't actually called the clone method.
I have to provide it.
If you implement a substrate,
you've got to implement the super trait above it,
even if you don't actually use it yet.
I could have done, of course,
I could have said in my main code here,
I could have said C1.clone
but I didn't need to in my demo.
One last thing I want to discuss
is what if you don't implement copy at all?
So back in my structure,
I've commented out the copy
and clone implementation there
and I'm going to also comment out
the manual implementation here.
Okay, so what that means,
what that means is that my currency structure
doesn't support copy and behavior.
So remember what happens
when you assign things that don't implement copy?
It doesn't move, okay?
So C1 was $10.99,
and because currency doesn't implement copy anymore,
when I say C2 equals C1
it'll move ownership of the data from C1 into C2.
If you don't implement copy,
then a move occurs
the data will be moved into C2
and C1 will be vacated, okay?
We've looked at this a lot.
This is the whole idea of ownership in Rust.
When you assign with types
that don't implement copy
it moves ownership of the data
from here into here,
it means this object can no longer be used.
Once you've moved data out of C1
you can't use C1 anymore.
Okay, so I'm going to get an error now,
all I wanted to do was to copy the data
but it didn't copy.
It moved away from C1 into C2.
C1 is no longer usable afterwards
which is a terrible shame.
It's a crying shame.
Well, we knew that, didn't we?
It said C1 currency.
The currency structure doesn't implement the copy trait.
Therefore a move occurs here
because we didn't tell it
we wanted copy behavior.
So it moved ownership from C1 into C2,
which means that C1 can't be used anymore
because it's been moved.
C1 is effectively like a dead object now.
The data doesn't live here anymore.
It's been moved into C2.
So the recommendation
is for simple types,
for structures that are effectively just like values
that want to behave as if they just be copied.
I can just copy the data from here to here
as a bitwise copy that actually makes sense.
Then in that case you do want to implement copy
and clone.
And in most cases
the default implementation will be fine
as long as your fields implement copying themselves.
And if they don't
and you want something more exotic
then you can always implement copy and clone manually
as we've done down here if you need to.
Okay, so one way or the other
you can implement copy behavior
and that means when you assign one variable to another
it just does a bitwise copy now
instead of trying to move data away.
Okay so the application works again.