@ -111,10 +111,10 @@ Casting with ```as``` is useful because Rust always needs to know the type of th
```rust
fn main() {
let my_number = 100; // We didn't write a type of integer,
let my_number = 100; // We didn't write a type of integer,
// so Rust chooses i32. Rust always
// chooses i32 for integers if you don't
// tell it to use a different type
// chooses i32 for integers if you don't
// tell it to use a different type
println!("{}", my_number as char);
}
@ -167,6 +167,7 @@ So usually the compiler can guess. But sometimes you need to tell it, for two re
2) You want a different type (for example, you want an ```i128```, not an ```i32```).
To specify a type, add a colon after the variable name.
```rust
fn main() {
let small_number: u8 = 10;
@ -182,6 +183,7 @@ fn main() {
```
You can also add ```_``` if you want to make the number easy to read.
```rust
fn main() {
let small_number = 10_u8; // This is easier to read
@ -193,7 +195,7 @@ The ```_``` does not change the number. It is only to make it easy for you to re
```rust
fn main() {
let number = 0________u8;
let number = 0________u8;
let number2 = 1___6______2____4______i32;
println!("{}, {}", number, number2);
}
@ -409,7 +411,7 @@ fn main() {
let my_number = 8; // my_number starts here
// my_number ends here!
}
println!("Hello, number {}", my_number); // there is no my_number and
// println!() can't find it
}
@ -420,9 +422,9 @@ You can use a code block to return a value:
```rust
fn main() {
let my_number = {
let second_number = 8;
let second_number = 8;
second_number + 9 // No semicolon, so the code block returns 8 + 9.
// It works just like a function
// It works just like a function
};
println!("My number is: {}", my_number);
@ -434,9 +436,9 @@ If you add a semicolon inside the block, it will return ```()``` (nothing):
```rust
fn main() {
let my_number = {
let second_number = 8; // declare second_number,
let second_number = 8; // declare second_number,
second_number + 9; // add 9 to second_number
// but we didn't return it!
// but we didn't return it!
// second_number dies now
};
@ -519,7 +521,7 @@ The smallest i32 is -2147483648 and the biggest i32 is 2147483647.
The smallest u32 is 0 and the biggest u32 is 4294967295.
The smallest i64 is -9223372036854775808 and the biggest i64 is 9223372036854775807.
The smallest u64 is 0 and the biggest u64 is 18446744073709551615.
The smallest i128 is -170141183460469231731687303715884105728 and the biggest i128 is 170141183460469231731687303715884105727.
The smallest i128 is -170141183460469231731687303715884105728 and the biggest i128 is 170141183460469231731687303715884105727.
The smallest u128 is 0 and the biggest u128 is 340282366920938463463374607431768211455.
```
@ -620,7 +622,7 @@ Without shadowing you would have to think of different names, even though you do
```rust
fn main() {
// Pretending we are using Rust without shadowing
// Pretending we are using Rust without shadowing
let final_number = {
let y = 10;
let x = 9; // x starts at 9
@ -663,8 +665,8 @@ So this is like five pointers. Where is the chapter "My life"? It's on page 1 (i
A pointer in Rust is usually called a **reference**. A reference means you *borrow* the value, but you don't own it. In Rust, references have a ```&```. So:
* ```let my_variable = 8``` makes a regular variable, but
* ```let my_reference = &my_variable``` makes a reference.
* ```let my_variable = 8``` makes a regular variable, but
* ```let my_reference = &my_variable``` makes a reference.
This means that ```my_reference``` is only looking at the data of ```my_variable```. ```my_variable``` still owns its data.
@ -785,7 +787,7 @@ You can even write emojis thanks to UTF-8.
```rust
fn main() {
let name = "😂";
println!("My name is actually {}", name);
println!("My name is actually {}", name);
}
```
@ -801,7 +803,6 @@ fn main() {
println!("And an f64 is always {:?} bytes. It is Sized.", std::mem::size_of::<f64>());
println!("But a &str? It can be anything. '서태지' is {:?} bytes. It is not Sized.", std::mem::size_of_val("서태지")); // std::mem::size_of_val() gives you the size in bytes of a variable
println!("And 'Adrian Fahrenheit Țepeș' is {:?} bytes. It is not Sized.", std::mem::size_of_val("Adrian Fahrenheit Țepeș"));
}
```
@ -864,7 +865,7 @@ There are two types that don't use ```let``` to declare: ```const``` and ```stat
So they are almost the same. Rust programmers almost always use ```const```.
You write them with ALL CAPITAL LETTERS, and usually outside of the ```main``` function.
You write them with ALL CAPITAL LETTERS, and usually outside of the ```main``` function.
Two examples are: ```const NUMBER_OF_MONTHS: u32 = 12;``` and ```const SEASONS: [&str; 4] = ["Spring", "Summer", "Fall", "Winter"];```
@ -919,7 +920,7 @@ So let's use it to add 10 to my_number. But you can't write ```num_ref += 10```,
```rust
fn main() {
let mut my_number = 8;
let mut my_number = 8;
let num_ref = &mut my_number;
*num_ref += 10; // Use * to change the i32 value.
println!("{}", my_number);
@ -938,7 +939,7 @@ This is because mutable references can change the data. You could get problems i
A good way to understand is to think of a Powerpoint presentation.
Situation one is about only one mutable reference.
Situation one is about only one mutable reference.
Situation one: An employee is writing a Powerpoint presentation. He wants his manager to help him. The employee gives his login information to his manager, and asks him to help by making edits. Now the manager has a "mutable reference" to the employee's presentation. This is fine, because nobody else is looking at the presentation.
@ -955,10 +956,10 @@ Here is an example of a mutable borrow with an immutable borrow:
```rust
fn main() {
let mut number = 10;
let number_ref = &number;
let number_change = &mut number;
let number_ref = &number;
let number_change = &mut number;
*number_change += 10;
println!("{}", number_ref);
println!("{}", number_ref);
}
```
@ -1306,7 +1307,7 @@ The compiler says "seasons isn't type () and seasons2 isn't type () either!" as
error[E0308]: mismatched types
--> src\main.rs:4:9
|
4 | let () = seasons;
4 | let () = seasons;
| ^^ ------- this expression has type `[&str; 4]`
| |
| expected array `[&str; 4]`, found `()`
@ -1336,7 +1337,7 @@ This method is used a lot to create buffers. For example, ```let mut buffer = [0
You can index (get) entries in an array with []. The first entry is [0], the second is [1], and so on.
```rust
fn main() {
fn main() {
let my_numbers = [0, 10, -20];
println!("{}", my_numbers[1]); // prints 10
}
@ -1380,14 +1381,13 @@ There are two main ways to declare a vector. One is like with ```String``` using
fn main() {
let name1 = String::from("Windy");
let name2 = String::from("Gomesy");
let mut my_vec = Vec::new();
// If we run the program now, the compiler will give an error.
// It doesn't know the type of vec.
my_vec.push(name1); // Now it knows: it's Vec<String>
my_vec.push(name2);
}
```
@ -1417,7 +1417,7 @@ You can slice a vector too, just like in an array.
if all_have_at_least_10 { // Check if it's still true, and print if true
println!("Each colour has at least 10.")
}
}
fn main() {
@ -2326,8 +2318,7 @@ fn main() {
match_colours(first);
match_colours(second);
match_colours(third);
match_colours(third);
}
```
@ -2411,7 +2402,7 @@ The animal is a cat
## Self
Remember that Self (the type Self) and self (the variable self) are abbreviations. (abbreviation = short way to write)
Remember that Self (the type Self) and self (the variable self) are abbreviations. (abbreviation = short way to write)
So in our code, Self = AnimalType. Also, ```fn change_to_dog(&mut self)``` means ```fn change_to_dog(&mut AnimalType)```
@ -2537,7 +2528,7 @@ fn main() {
name: "Charlie".to_string(),
age: 1,
};
let number = 55;
print_item(charlie);
@ -2552,7 +2543,7 @@ Here is your item: Animal { name: "Charlie", age: 1 }
Here is your item: 55
```
Sometimes we need more than one type in a generic function. We have to write out each type name, and think about how we want to use it. In this example, we want two types. First we want to print a statement for type T. Printing with ```{}``` is nicer, so we will require Display for T.
Sometimes we need more than one type in a generic function. We have to write out each type name, and think about how we want to use it. In this example, we want two types. First we want to print a statement for type T. Printing with ```{}``` is nicer, so we will require Display for T.
Next is type U, and two variables have type U (U is some sort of number). We want to compare them, so we need PartialOrd. We want to print them too, so we require Display for U as well.
The important point to remember: with ```Some```, you have a value of type ```T``` (any type). But with ```None```, you don't have anything. So in a ```match``` statement for Option you can't say:
```rust
Some(value) => println!("The value is {}", value),
None(value) => println!("The value is {}", value),
Some(value) => println!("The value is {}", value),
None(value) => println!("The value is {}", value),
How did we find std::num::ParseIntError? One easy way is to "ask" the compiler again.
How did we find std::num::ParseIntError? One easy way is to "ask" the compiler again.
```rust
fn main() {
@ -3281,7 +3271,7 @@ fn main() {
This is okay, but we don't want to print "The dog is running". We can change the method .run(), but we have to follow the signature. The signature says:
```rust
fn run(&self) {
fn run(&self) {
println!("The dog is running!");
}
```
@ -3289,7 +3279,7 @@ This is okay, but we don't want to print "The dog is running". We can change the
The signature says "fn run() takes &self, and returns nothing". So you can't do this:
```rust
fn run(&self) -> i32 {
fn run(&self) -> i32 {
5
}
```
@ -3570,8 +3560,8 @@ And here is an example of functional style:
```rust
fn main() {
let new_vec = (1..=10).collect::<Vec<i32>>();
// Or you can write it like this:
// let new_vec: Vec<i32> = (1..=10).collect();
// Or you can write it like this:
// let new_vec: Vec<i32> = (1..=10).collect();
println!("{:?}", new_vec);
}
```
@ -3684,7 +3674,7 @@ impl Library {
fn new() -> Self { // this creates a new Library
Self {
library_type: LibraryType::City, // most are in the city so we'll choose City
library_type: LibraryType::City, // most are in the city so we'll choose City
// most of the time
books: Vec::new(),
}
@ -3697,7 +3687,6 @@ fn main() {
my_library.add_book("Demian - die Geschichte einer Jugend");
my_library.add_book("구운몽");
my_library.add_book("吾輩は猫である");
println!("{:?}", my_library.books); // we can print our list of books
}
@ -3711,7 +3700,7 @@ That works well. Now we want to implement ```Iterator``` for the library so we c
}
```
It says:
It says:
```
error[E0277]: `Library` is not an iterator
@ -4000,7 +3989,7 @@ fn main() {
}
```
Rust says that
Rust says that
```
error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments
@ -4321,14 +4310,12 @@ struct City {
}
fn main() {
let my_city = City {
name: "Ichinomiya",
date_founded: 1921,
};
};
println!("{} was founded in {}", my_city.name, my_city.date_founded);
}
```
@ -4342,16 +4329,14 @@ struct City {
}
fn main() {
let city_names = vec!["Ichinomiya".to_string(), "Kurume".to_string()]; // city_names does not live for the whole program
let my_city = City {
name: &city_names[0], // This is a &str, but not a &'static str. It is a reference to a value inside city_names
date_founded: 1921,
};
};
println!("{} was founded in {}", my_city.name, my_city.date_founded);
}
```
@ -4381,16 +4366,14 @@ struct City<'a> { // City has lifetime 'a
}
fn main() {
let city_names = vec!["Ichinomiya".to_string(), "Kurume".to_string()];
let my_city = City {
name: &city_names[0],
date_founded: 1921,
};
};
println!("{} was founded in {}", my_city.name, my_city.date_founded);
}
```
@ -4421,13 +4404,13 @@ The same is true for lifetimes. When you write 'a here:
```rust
#[derive(Debug)]
struct City<'a> {
struct City<'a> {
name: &'a str,
date_founded: u32,
}
```
It means "please only take an input for ```name``` if it lives at least as long as ```City```".
It means "please only take an input for ```name``` if it lives at least as long as ```City```".
It does not mean: "I will make the input for ```name``` live as long as ```City```".
@ -4493,8 +4476,7 @@ fn main() {
};
// 10 years later, super_phone_3000 is not on sale anymore
super_phone_3000.on_sale.set(false);
super_phone_3000.on_sale.set(false);
}
```
@ -4529,16 +4511,15 @@ fn main() {
};
println!("{:?}", user_1.active);
}
```
This prints ```RefCell { value: true }```.
There are many methods for ```RefCell```. Two of them are ```.borrow()``` and ```.borrow_mut()```. With these methods, you can do the same thing you do with ```&``` and ```&mut```. The rules are the same:
There are many methods for ```RefCell```. Two of them are ```.borrow()``` and ```.borrow_mut()```. With these methods, you can do the same thing you do with ```&``` and ```&mut```. The rules are the same:
* Many borrows is fine,
* one mutable borrow is fine,
* Many borrows is fine,
* one mutable borrow is fine,
* but mutable and immutable together is not fine.
So changing the value in a ```RefCell``` is very easy:
@ -4612,17 +4593,16 @@ fn main() {
// It has to be mut because we will change it
// Now it has access to the Mutex
// Let's print my_mutex to see:
println!("{:?}", my_mutex); // This prints "Mutex { data: <locked> }"
// So we can't access the data with my_mutex now,
// only with mutex_changer
println!("{:?}", mutex_changer); // This prints 5. Let's change it to 6.
*mutex_changer = 6; // mutex_changer is a MutexGuard<i32> so we use * to change the i32
println!("{:?}", mutex_changer); // Now it says 6
}
```
@ -4644,9 +4624,9 @@ fn main() {
If you don't want to use a different ```{}``` code block, you can use ```std::mem::drop(mutex_changer)```. ```std::mem::drop``` means "make this go out of scope".
```rust
use std::sync::Mutex;
```rust
fn main() {
let my_mutex = Mutex::new(5);
let mut mutex_changer = my_mutex.lock().unwrap();
@ -4672,7 +4652,6 @@ fn main() {
// and will wait forever.
println!("This will never print...");
}
```
@ -4686,13 +4665,12 @@ fn main() {
let mut mutex_changer = my_mutex.lock().unwrap();
let mut other_mutex_changer = my_mutex.try_lock(); // try to get the lock
if let Ok(value) = other_mutex_changer { //
if let Ok(value) = other_mutex_changer {
println!("The MutexGuard has: {}", value)
} else {
println!("Didn't get the lock")
}
}
}
```
Also, you don't need to make a variable to change the ```Mutex```. You can just do this:
@ -4791,7 +4769,6 @@ fn main() {
} else {
println!("Couldn't get write access, sorry!")
};
}
```
@ -4802,9 +4779,9 @@ Cow is a very convenient enum. It means "clone on write" and lets you return a `
To understand it, let's look at the signature. It says:
```rust
pub enum Cow<'a, B>
pub enum Cow<'a, B>
where
B: 'a + ToOwned + ?Sized,
B: 'a + ToOwned + ?Sized,
{
Borrowed(&'a B),
Owned(<BasToOwned>::Owned),
@ -4827,7 +4804,6 @@ Here is an example to test ```Cow```. We will put a number into a function that
use std::borrow::Cow;
fn modulo_3(input: u8) -> Cow<'static, str> {
match input % 3 {
0 => "Remainder is 0".into(),
1 => "Remainder is 1".into(),
@ -4841,7 +4817,7 @@ fn main() {
Cow::Borrowed(message) => println!("{} went in. The Cow is borrowed with this message: {}", number, message),
Cow::Owned(message) => println!("{} went in. The Cow is owned with this message: {}", number, message),
}
}
}
}
```
@ -4871,7 +4847,7 @@ type CharacterVec = Vec<char>;