Rewrite copy types

pull/67/head
Dhghomon 4 years ago committed by GitHub
parent be8d06bf93
commit e97165471e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1559,9 +1559,9 @@ Remember our employee Powerpoint and manager situation above? In this situation
## Copy types
Some types in Rust are very simple. They are called **copy types**. These simple types are all on the stack, and the compiler knows their size. That means that they are very easy to copy, so the compiler always copies when you send it to a function. So you don't need to worry about ownership.
Some types in Rust are very simple. They are called **copy types**. These simple types are all on the stack, and the compiler knows their size. That means that they are very easy to copy, so the compiler always copies when you send it to a function. It always copies because they are so small and easy that there is no reason not to copy. So you don't need to worry about ownership for these types.
These simple types include: integers, floats, booleans (true and false), and char.
These simple types include: integers, floats, booleans (`true` and `false`), and `char`.
How do you know if a type **implements** copy? (implements = can use) You can check the documentation. For example, here is the documentation for char:
@ -1574,38 +1574,38 @@ On the left you can see **Trait Implementations**. You can see for example **Cop
- can use `{:?}` to print (**Debug**)
```rust
fn prints_number(number: i32) { // There is no -> so it's not returning anything
// If number was not copy type, it would take it
// and we couldn't use it again
println!("{}", number);
}
fn main() {
let my_number = 8;
prints_number(my_number); // Prints 8. prints_number gets a copy of my_number
prints_number(my_number); // Prints 8 again.
// No problem, because my_number is copy type!
}
fn prints_number(number: i32) { // No return with ->
// If number was not copy type, it would take it
// and we couldn't use it again
println!("{}", number);
}
```
But if you look at the documentation for String, it is not copy type.
[https://doc.rust-lang.org/std/string/struct.String.html](https://doc.rust-lang.org/std/string/struct.String.html)
On the left in **Trait Implementations** you can look in alphabetical order. A, B, C... there is no **Copy** in C. But there is **Clone**. **Clone** is similar to **Copy**, but needs more memory.
On the left in **Trait Implementations** you can look in alphabetical order. A, B, C... there is no **Copy** in C. But there is **Clone**. **Clone** is similar to **Copy**, but usually needs more memory. Also, you have to call it with `.clone()` - it won't clone just by itself.
In this example, `prints_country()` prints the country name, a `String`. We want to print it two times, but we can't:
```rust
fn prints_country(country_name: String) {
println!("{}", country_name);
}
fn main() {
let country = String::from("Kiribati");
prints_country(country);
prints_country(country); // ⚠️
}
fn prints_country(country_name: String) {
println!("{}", country_name);
}
```
But now we understand the message.
@ -1622,59 +1622,64 @@ error[E0382]: use of moved value: `country`
| ^^^^^^^ value used here after move
```
The important part is `which does not implement the Copy trait`. But in the documentation we saw that String implements the Clone trait. So we can add `.clone()`. This creates a clone, and we send the clone to the function. `country` is still alive, so we can use it.
The important part is `which does not implement the Copy trait`. But in the documentation we saw that String implements the `Clone` trait. So we can add `.clone()` to our code. This creates a clone, and we send the clone to the function. Now `country` is still alive, so we can use it.
```rust
fn prints_country(country_name: String) {
println!("{}", country_name);
}
fn main() {
let country = String::from("Kiribati");
prints_country(country.clone()); // make a clone and give it to the function
prints_country(country.clone()); // make a clone and give it to the function. Only the clone goes in, and country is still alive
prints_country(country);
}
fn prints_country(country_name: String) {
println!("{}", country_name);
}
```
Of course, if the `String` is very large, `.clone()` can use a lot of memory. For example, one `String` can be a whole book, and every time we call `.clone()` it will copy the book. So using `&` for a reference is faster, if you can.
Of course, if the `String` is very large, `.clone()` can use a lot of memory. One `String` can be a whole book in length, and every time we call `.clone()` it will copy the book. So using `&` for a reference is faster, if you can. For example, this code pushes a `&str` onto a `String` and then makes a clone every time it gets used in a function:
```rust
fn main() {
let mut country = String::from("Kiribati"); // country is mutable
let country_ref = &country; // country_ref needs a reference
changes_country(&mut country); // changes_country needs a &mut ref
println!("{}", country_ref); // ⚠️ immutable and mutable borrow together
fn get_length(input: String) { // Takes ownership of a String
println!("It's {} words long.", input.split_whitespace().count()); // splits to count the number of words
}
fn prints_country(country_name: String) {
println!("{}", country_name);
fn main() {
let mut my_string = String::new();
for _ in 0..50 {
my_string.push_str("Here are some more words "); // push the words on
get_length(my_string.clone()); // gives it a clone every time
}
}
````
fn changes_country(country_name: &mut String) {
country_name.push_str(" is a country");
println!("{}", country_name);
}
It prints:
```text
It's 5 words long.
It's 10 words long.
...
It's 250 words long.
```
Maybe we can change the order, but we can also just `.clone()`.
That's 50 clones. Here it is using a reference instead, which is better:
```rust
fn main() {
let mut country = String::from("Kiribati"); // country is mutable
let country_ref = &country; // country_ref needs a reference
changes_country(&mut country.clone()); // give changes_country a clone instead
println!("{}", country_ref); // now the code works
fn get_length(input: &String) {
println!("It's {} words long.", input.split_whitespace().count());
}
fn prints_country(country_name: String) {
println!("{}", country_name);
fn main() {
let mut my_string = String::new();
for _ in 0..50 {
my_string.push_str("Here are some more words ");
get_length(&my_string);
}
}
````
Instead of 50 clones, it's zero.
fn changes_country(country_name: &mut String) {
country_name.push_str(" is a country");
println!("{}", country_name);
}
```
### Variables without values

Loading…
Cancel
Save