From 5b78bd21de097d090f61b099f928c2d013acdd94 Mon Sep 17 00:00:00 2001 From: Dhghomon <56599343+Dhghomon@users.noreply.github.com> Date: Tue, 14 Jul 2020 11:32:08 +0900 Subject: [PATCH] More on Copy types --- README.md | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 127 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1b8b55e..000e338 100644 --- a/README.md +++ b/README.md @@ -918,9 +918,9 @@ fn add_hungary(country_name: &mut String) { So to conclude: -* 1) fn function_name(variable: String) takes a ```String``` and owns it. If it doesn't return anything, then the variable dies after the function is done. -* 2) fn function_name(variable: &String) borrows a ```String``` and can look at it -* 3) fn function_name(variable: &mut String) borrows a ```String``` and can change it +* ```fn function_name(variable: String)``` takes a ```String``` and owns it. If it doesn't return anything, then the variable dies after the function is done. +* ```fn function_name(variable: &String)``` borrows a ```String``` and can look at it +* ```fn function_name(variable: &mut String)``` borrows a ```String``` and can change it Here is an example that looks like a mutable reference, but it is different. @@ -938,6 +938,130 @@ fn adds_hungary(mut country: String) { // but adds_hungary takes the string and How is this possible? It is because ```mut hungary``` is not a reference: ```adds_hungary``` owns ```country``` now. (Remember, it takes ```String``` and not ```&String```). ```adds_hungary``` is the full owner, so it can take ```country``` as mutable. +# 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. + +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: + +https://doc.rust-lang.org/std/primitive.char.html + +On the left you can see **Trait Implementations**. You can see for example **Copy**, **Debug**, and **Display**. So you know that a ```char```: + +* is copied when you send it to a function (**Copy**) +* can use ```{}``` to print (**Display**) +* can use ```{:?}``` to print (**Debug**) + + +```rust +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! +} + +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 + +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. + +In this example, ```prints_country()``` prints the country name, a ```String```. We want to print it two times, but we can't: + +```rust +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. + +``` +error[E0382]: use of moved value: `country` + --> src\main.rs:4:20 + | +2 | let country = String::from("Kiribati"); + | ------- move occurs because `country` has type `std::string::String`, which does not implement the `Copy` trait +3 | prints_country(country); + | ------- value moved here +4 | prints_country(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. + +```rust +fn main() { + let country = String::from("Kiribati"); + prints_country(country.clone()); // make a clone and give it to the function + 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. + +```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 prints_country(country_name: String) { + println!("{}", country_name); +} + +fn changes_country(country_name: &mut String) { + country_name.push_str(" is a country"); + println!("{}", country_name); +} +``` + +Maybe we can change the order, but we can also just ```.clone()```. + +```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 prints_country(country_name: String) { + println!("{}", country_name); +} + +fn changes_country(country_name: &mut String) { + country_name.push_str(" is a country"); + println!("{}", country_name); +} +``` + + + # Collection types