{"doc_urls":["Chapter_0.html#updates","Chapter_1.html#introduction","Chapter_2.html#who-am-i","Chapter_3.html#writing-rust-in-easy-english","Chapter_3.html#part-1---rust-in-your-browser","Chapter_4.html#rust-playground","Chapter_5.html#-and-","Chapter_6.html#comments","Chapter_7.html#types","Chapter_7.html#primitive-types","Chapter_8.html#type-inference","Chapter_8.html#floats","Chapter_9.html#printing-hello-world","Chapter_9.html#declaring-variables-and-code-blocks","Chapter_10.html#display-and-debug","Chapter_10.html#smallest-and-largest-numbers","Chapter_11.html#mutability-changing","Chapter_11.html#shadowing","Chapter_12.html#the-stack-the-heap-and-pointers","Chapter_13.html#more-about-printing","Chapter_14.html#strings","Chapter_15.html#const-and-static","Chapter_16.html#more-on-references","Chapter_17.html#mutable-references","Chapter_17.html#shadowing-again","Chapter_18.html#giving-references-to-functions","Chapter_19.html#copy-types","Chapter_19.html#variables-without-values","Chapter_20.html#collection-types","Chapter_20.html#arrays","Chapter_21.html#vectors","Chapter_22.html#tuples","Chapter_23.html#control-flow","Chapter_24.html#structs","Chapter_25.html#enums","Chapter_25.html#enums-to-use-multiple-types","Chapter_26.html#loops","Chapter_27.html#implementing-structs-and-enums","Chapter_28.html#destructuring","Chapter_29.html#references-and-the-dot-operator","Chapter_30.html#generics","Chapter_31.html#option-and-result","Chapter_31.html#option","Chapter_31.html#result","Chapter_32.html#other-collections","Chapter_32.html#hashmap-and-btreemap","Chapter_32.html#hashset-and-btreeset","Chapter_32.html#binaryheap","Chapter_32.html#vecdeque","Chapter_33.html#the--operator","Chapter_33.html#when-panic-and-unwrap-are-good","Chapter_34.html#traits","Chapter_34.html#the-from-trait","Chapter_34.html#taking-a-string-and-a-str-in-a-function","Chapter_35.html#chaining-methods","Chapter_36.html#iterators","Chapter_36.html#how-an-iterator-works","Chapter_37.html#closures","Chapter_37.html#_-in-a-closure","Chapter_37.html#helpful-methods-for-closures-and-iterators","Chapter_38.html#the-dbg-macro-and-inspect","Chapter_39.html#types-of-str","Chapter_40.html#lifetimes","Chapter_41.html#interior-mutability","Chapter_41.html#cell","Chapter_41.html#refcell","Chapter_41.html#mutex","Chapter_41.html#rwlock","Chapter_42.html#cow","Chapter_43.html#type-aliases","Chapter_43.html#importing-and-renaming-inside-a-function","Chapter_44.html#the-todo-macro","Chapter_45.html#rc","Chapter_46.html#multiple-threads","Chapter_47.html#closures-in-functions","Chapter_48.html#impl-trait","Chapter_49.html#arc","Chapter_50.html#channels","Chapter_51.html#reading-rust-documentation","Chapter_51.html#assert_eq","Chapter_51.html#searching","Chapter_51.html#src-button","Chapter_51.html#information-on-traits","Chapter_52.html#attributes","Chapter_53.html#box","Chapter_54.html#box-around-traits","Chapter_55.html#default-and-the-builder-pattern","Chapter_56.html#deref-and-derefmut","Chapter_57.html#crates-and-modules","Chapter_58.html#testing","Chapter_58.html#test-driven-development","Chapter_59.html#external-crates","Chapter_59.html#rand","Chapter_59.html#rayon","Chapter_59.html#serde","Chapter_59.html#regex","Chapter_59.html#chrono","Chapter_60.html#a-tour-of-the-standard-library","Chapter_60.html#arrays","Chapter_60.html#char","Chapter_60.html#integers","Chapter_60.html#floats","Chapter_60.html#bool","Chapter_60.html#vec","Chapter_60.html#string","Chapter_60.html#osstring-and-cstring","Chapter_60.html#mem","Chapter_60.html#prelude","Chapter_60.html#time","Chapter_60.html#other-macros","Chapter_61.html#writing-macros","Chapter_61.html#part-2---rust-on-your-computer","Chapter_62.html#cargo","Chapter_63.html#taking-user-input","Chapter_64.html#using-files","Chapter_65.html#cargo-doc","Chapter_66.html#the-end"],"index":{"documentStore":{"docInfo":{"0":{"body":55,"breadcrumbs":2,"title":1},"1":{"body":79,"breadcrumbs":2,"title":1},"10":{"body":142,"breadcrumbs":4,"title":2},"100":{"body":326,"breadcrumbs":4,"title":1},"101":{"body":198,"breadcrumbs":4,"title":1},"102":{"body":161,"breadcrumbs":4,"title":1},"103":{"body":150,"breadcrumbs":4,"title":1},"104":{"body":313,"breadcrumbs":4,"title":1},"105":{"body":194,"breadcrumbs":5,"title":2},"106":{"body":506,"breadcrumbs":4,"title":1},"107":{"body":334,"breadcrumbs":4,"title":1},"108":{"body":372,"breadcrumbs":4,"title":1},"109":{"body":521,"breadcrumbs":4,"title":1},"11":{"body":222,"breadcrumbs":3,"title":1},"110":{"body":1008,"breadcrumbs":4,"title":2},"111":{"body":47,"breadcrumbs":6,"title":4},"112":{"body":471,"breadcrumbs":2,"title":1},"113":{"body":642,"breadcrumbs":6,"title":3},"114":{"body":947,"breadcrumbs":4,"title":2},"115":{"body":210,"breadcrumbs":4,"title":2},"116":{"body":42,"breadcrumbs":2,"title":1},"12":{"body":275,"breadcrumbs":6,"title":3},"13":{"body":101,"breadcrumbs":7,"title":4},"14":{"body":132,"breadcrumbs":4,"title":2},"15":{"body":170,"breadcrumbs":5,"title":3},"16":{"body":74,"breadcrumbs":4,"title":2},"17":{"body":232,"breadcrumbs":3,"title":1},"18":{"body":235,"breadcrumbs":6,"title":3},"19":{"body":758,"breadcrumbs":4,"title":2},"2":{"body":21,"breadcrumbs":0,"title":0},"20":{"body":369,"breadcrumbs":2,"title":1},"21":{"body":71,"breadcrumbs":4,"title":2},"22":{"body":120,"breadcrumbs":4,"title":2},"23":{"body":402,"breadcrumbs":4,"title":2},"24":{"body":90,"breadcrumbs":4,"title":2},"25":{"body":288,"breadcrumbs":6,"title":3},"26":{"body":345,"breadcrumbs":4,"title":2},"27":{"body":150,"breadcrumbs":5,"title":3},"28":{"body":26,"breadcrumbs":4,"title":2},"29":{"body":281,"breadcrumbs":3,"title":1},"3":{"body":243,"breadcrumbs":8,"title":4},"30":{"body":430,"breadcrumbs":2,"title":1},"31":{"body":243,"breadcrumbs":2,"title":1},"32":{"body":596,"breadcrumbs":4,"title":2},"33":{"body":323,"breadcrumbs":2,"title":1},"34":{"body":491,"breadcrumbs":2,"title":1},"35":{"body":159,"breadcrumbs":5,"title":4},"36":{"body":595,"breadcrumbs":2,"title":1},"37":{"body":287,"breadcrumbs":6,"title":3},"38":{"body":191,"breadcrumbs":2,"title":1},"39":{"body":190,"breadcrumbs":6,"title":3},"4":{"body":59,"breadcrumbs":8,"title":4},"40":{"body":563,"breadcrumbs":2,"title":1},"41":{"body":16,"breadcrumbs":4,"title":2},"42":{"body":389,"breadcrumbs":3,"title":1},"43":{"body":548,"breadcrumbs":3,"title":1},"44":{"body":36,"breadcrumbs":2,"title":1},"45":{"body":750,"breadcrumbs":3,"title":2},"46":{"body":530,"breadcrumbs":3,"title":2},"47":{"body":224,"breadcrumbs":2,"title":1},"48":{"body":291,"breadcrumbs":2,"title":1},"49":{"body":298,"breadcrumbs":2,"title":1},"5":{"body":132,"breadcrumbs":4,"title":2},"50":{"body":610,"breadcrumbs":4,"title":3},"51":{"body":1363,"breadcrumbs":2,"title":1},"52":{"body":415,"breadcrumbs":2,"title":1},"53":{"body":199,"breadcrumbs":5,"title":4},"54":{"body":198,"breadcrumbs":4,"title":2},"55":{"body":213,"breadcrumbs":2,"title":1},"56":{"body":417,"breadcrumbs":3,"title":2},"57":{"body":802,"breadcrumbs":2,"title":1},"58":{"body":89,"breadcrumbs":3,"title":2},"59":{"body":1873,"breadcrumbs":5,"title":4},"6":{"body":48,"breadcrumbs":0,"title":0},"60":{"body":249,"breadcrumbs":6,"title":3},"61":{"body":62,"breadcrumbs":4,"title":2},"62":{"body":976,"breadcrumbs":2,"title":1},"63":{"body":0,"breadcrumbs":4,"title":2},"64":{"body":233,"breadcrumbs":3,"title":1},"65":{"body":203,"breadcrumbs":3,"title":1},"66":{"body":302,"breadcrumbs":3,"title":1},"67":{"body":130,"breadcrumbs":3,"title":1},"68":{"body":236,"breadcrumbs":2,"title":1},"69":{"body":219,"breadcrumbs":4,"title":2},"7":{"body":133,"breadcrumbs":2,"title":1},"70":{"body":215,"breadcrumbs":6,"title":4},"71":{"body":243,"breadcrumbs":4,"title":2},"72":{"body":418,"breadcrumbs":2,"title":1},"73":{"body":582,"breadcrumbs":4,"title":2},"74":{"body":456,"breadcrumbs":4,"title":2},"75":{"body":531,"breadcrumbs":4,"title":2},"76":{"body":568,"breadcrumbs":2,"title":1},"77":{"body":493,"breadcrumbs":2,"title":1},"78":{"body":14,"breadcrumbs":6,"title":3},"79":{"body":168,"breadcrumbs":4,"title":1},"8":{"body":12,"breadcrumbs":2,"title":1},"80":{"body":30,"breadcrumbs":4,"title":1},"81":{"body":91,"breadcrumbs":5,"title":2},"82":{"body":47,"breadcrumbs":5,"title":2},"83":{"body":371,"breadcrumbs":2,"title":1},"84":{"body":269,"breadcrumbs":2,"title":1},"85":{"body":398,"breadcrumbs":6,"title":3},"86":{"body":1067,"breadcrumbs":6,"title":3},"87":{"body":741,"breadcrumbs":4,"title":2},"88":{"body":677,"breadcrumbs":4,"title":2},"89":{"body":569,"breadcrumbs":2,"title":1},"9":{"body":607,"breadcrumbs":3,"title":2},"90":{"body":1298,"breadcrumbs":4,"title":3},"91":{"body":78,"breadcrumbs":4,"title":2},"92":{"body":548,"breadcrumbs":3,"title":1},"93":{"body":126,"breadcrumbs":3,"title":1},"94":{"body":43,"breadcrumbs":3,"title":1},"95":{"body":25,"breadcrumbs":3,"title":1},"96":{"body":19,"breadcrumbs":3,"title":1},"97":{"body":38,"breadcrumbs":6,"title":3},"98":{"body":104,"breadcrumbs":4,"title":1},"99":{"body":107,"breadcrumbs":4,"title":1}},"docs":{"0":{"body":"example workflow name 23 May 2021: Now available in Indonesian thanks to Ariandy / 1kb . 2 April 2021: Added BuyMeACoffee link for those who would like to buy me a coffee. 1 February 2021: Now available on YouTube! Two months later: all done as of 1 April 2021 for 186 videos in total (slightly over 23 hours). 22 December 2020: mdBook can be found here . 28 November 2020: Now also available in simplified Chinese thanks to kumakichi !","breadcrumbs":"Updates » Updates","id":"0","title":"Updates"},"1":{"body":"Rust is a new language that already has good textbooks. But sometimes its textbooks are difficult because they are for native English speakers. Many companies and people now learn Rust, and they could learn faster with a book that has easy English. This textbook is for these companies and people to learn Rust with simple English. Rust is a language that is quite new, but already very popular. It's popular because it gives you the speed and control of C or C++ but also the memory safety of other newer languages like Python. It does this with some new ideas that are sometimes different from other languages. That means that there are some new things to learn, and you can't just \"figure it out as you go along\". Rust is a language that you have to think about for a while to understand. But it still looks pretty familiar if you know another language and it is made to help you write good code.","breadcrumbs":"Introduction » Introduction","id":"1","title":"Introduction"},"10":{"body":"See this chapter on YouTube Type inference means that if you don't tell the compiler the type, but it can decide by itself, it will decide. The compiler always needs to know the type of the variables, but you don’t always need to tell it. Actually, usually you don't need to tell it. For example, for let my_number = 8, my_number will be an i32. That is because the compiler chooses i32 for integers if you don't tell it. But if you say let my_number: u8 = 8, it will make my_number a u8, because you told it u8. So usually the compiler can guess. But sometimes you need to tell it, for two reasons: You are doing something very complex and the compiler doesn't know the type you want. 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. fn main() { let small_number: u8 = 10;\n} For numbers, you can say the type after the number. You don't need a space - just type it right after the number. fn main() { let small_number = 10u8; // 10u8 = 10 of type u8\n} You can also add _ if you want to make the number easy to read. fn main() { let small_number = 10_u8; // This is easier to read let big_number = 100_000_000_i32; // 100 million is easy to read with _\n} The _ does not change the number. It is only to make it easy for you to read. And it doesn't matter how many _ you use: fn main() { let number = 0________u8; let number2 = 1___6______2____4______i32; println!(\"{}, {}\", number, number2);\n} This prints 0, 1624.","breadcrumbs":"Type inference » Type inference","id":"10","title":"Type inference"},"100":{"body":"There are a lot of math methods for these types, plus some others. Here are some of the most useful ones. .checked_add(), .checked_sub(), .checked_mul(), .checked_div(). These are good methods if you think you might get a number that won't fit into a type. They return an Option so you can safely check that your math works without making the program panic. fn main() { let some_number = 200_u8; let other_number = 200_u8; println!(\"{:?}\", some_number.checked_add(other_number)); println!(\"{:?}\", some_number.checked_add(1));\n} This prints: None\nSome(201) You'll notice that on the page for integers it says rhs a lot. This means \"right hand side\", which is the right hand side when you do some math. For example, in 5 + 6, 5 is on the left and 6 is on the right, so it's the rhs. This is not a keyword, but you will see it a lot so it's good to know. While we are on the subject, let's learn how to implement Add. After you implement Add, you can use + on a type that you create. You need to implement Add yourself because add can mean a lot of things. Here's the example in the standard library page: use std::ops::Add; // first bring in Add #[derive(Debug, Copy, Clone, PartialEq)] // PartialEq is probably the most important part here. You want to be able to compare numbers\nstruct Point { x: i32, y: i32,\n} impl Add for Point { type Output = Self; // Remember, this is called an \"associated type\": a \"type that goes together\". // In this case it's just another Point fn add(self, other: Self) -> Self { Self { x: self.x + other.x, y: self.y + other.y, } }\n} Now let's implement Add for our own type. Let's imagine that we want to add two countries together so we can compare their economies. It looks like this: use std::fmt;\nuse std::ops::Add; #[derive(Clone)]\nstruct Country { name: String, population: u32, gdp: u32, // This is the size of the economy\n} impl Country { fn new(name: &str, population: u32, gdp: u32) -> Self { Self { name: name.to_string(), population, gdp, } }\n} impl Add for Country { type Output = Self; fn add(self, other: Self) -> Self { Self { name: format!(\"{} and {}\", self.name, other.name), // We will add the names together, population: self.population + other.population, // and the population, gdp: self.gdp + other.gdp, // and the GDP } }\n} impl fmt::Display for Country { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, \"In {} are {} people and a GDP of ${}\", // Then we can print them all with just {} self.name, self.population, self.gdp ) }\n} fn main() { let nauru = Country::new(\"Nauru\", 10_670, 160_000_000); let vanuatu = Country::new(\"Vanuatu\", 307_815, 820_000_000); let micronesia = Country::new(\"Micronesia\", 104_468, 367_000_000); // We could have given Country a &str instead of a String for the name. But we would have to write lifetimes everywhere // and that would be too much for a small example. Better to just clone them when we call println!. println!(\"{}\", nauru.clone()); println!(\"{}\", nauru.clone() + vanuatu.clone()); println!(\"{}\", nauru + vanuatu + micronesia);\n} This prints: In Nauru are 10670 people and a GDP of $160000000\nIn Nauru and Vanuatu are 318485 people and a GDP of $980000000\nIn Nauru and Vanuatu and Micronesia are 422953 people and a GDP of $1347000000 Later on in this code we could change .fmt() to display a number that is easier to read. The three others are called Sub, Mul, and Div, and they are basically the same to implement. For +=, -=, *= and /=, just add Assign: AddAssign, SubAssign, MulAssign, and DivAssign. You can see the full list here , because there are many more. % for example is called Rem, - is called Neg, and so on.","breadcrumbs":"A tour of the standard library » Integers","id":"100","title":"Integers"},"101":{"body":"f32 and f64 have a very large number of methods that you use when doing math. We won't look at those, but here are some methods that you might use. They are: .floor(), .ceil(), .round(), and .trunc(). All of these return an f32 or f64 that is like an integer, with only 0 after the period. They do this: .floor(): gives you the next lowest integer. .ceil(): gives you the next highest integer. .round(): gives you a higher number if 0.5 or more, or the same number if less than 0.5. This is called rounding because it gives you a \"round\" number (a number that has a short, simple form). .trunc(): just cuts off the part after the period. Truncate means \"to cut off\". Here is a simple function to print them. fn four_operations(input: f64) { println!(\n\"For the number {}:\nfloor: {}\nceiling: {}\nrounded: {}\ntruncated: {}\\n\", input, input.floor(), input.ceil(), input.round(), input.trunc() );\n} fn main() { four_operations(9.1); four_operations(100.7); four_operations(-1.1); four_operations(-19.9);\n} This prints: For the number 9.1:\nfloor: 9\nceiling: 10\nrounded: 9 // because less than 9.5\ntruncated: 9 For the number 100.7:\nfloor: 100\nceiling: 101\nrounded: 101 // because more than 100.5\ntruncated: 100 For the number -1.1:\nfloor: -2\nceiling: -1\nrounded: -1\ntruncated: -1 For the number -19.9:\nfloor: -20\nceiling: -19\nrounded: -20\ntruncated: -19 f32 and f64 have a method called .max() and .min() that gives you the higher or the lower of two numbers. (For other types you can just use std::cmp::max and std::cmp::min.) Here is a way to use this with .fold() to get the highest or lowest number. You can see again that .fold() isn't just for adding numbers. fn main() { let my_vec = vec![8.0_f64, 7.6, 9.4, 10.0, 22.0, 77.345, 10.22, 3.2, -7.77, -10.0]; let maximum = my_vec.iter().fold(f64::MIN, |current_number, next_number| current_number.max(*next_number)); // Note: start with the lowest possible number for an f64. let minimum = my_vec.iter().fold(f64::MAX, |current_number, next_number| current_number.min(*next_number)); // And here start with the highest possible number println!(\"{}, {}\", maximum, minimum);\n}","breadcrumbs":"A tour of the standard library » Floats","id":"101","title":"Floats"},"102":{"body":"In Rust you can turn a bool into an integer if you want, because it's safe to do that. But you can't do it the other way around. As you can see, true turns to 1 and false turns to 0. fn main() { let true_false = (true, false); println!(\"{} {}\", true_false.0 as u8, true_false.1 as i32);\n} This prints 1 0. Or you can use .into() if you tell the compiler the type: fn main() { let true_false: (i128, u16) = (true.into(), false.into()); println!(\"{} {}\", true_false.0, true_false.1);\n} This prints the same thing. As of Rust 1.50 (released in February 2021), there is now a method called then(), which turns a bool into an Option. With then() you write a closure, and the closure is called if the item is true. Also, whatever is returned from the closure goes inside the Option. Here's a small example: fn main() { let (tru, fals) = (true.then(|| 8), false.then(|| 8)); println!(\"{:?}, {:?}\", tru, fals);\n} This just prints Some(8), None. And now a bit larger example: fn main() { let bool_vec = vec![true, false, true, false, false]; let option_vec = bool_vec .iter() .map(|item| { item.then(|| { // Put this inside of map so we can pass it on println!(\"Got a {}!\", item); \"It's true, you know\" // This goes inside Some if it's true // Otherwise it just passes on None }) }) .collect::>(); println!(\"Now we have: {:?}\", option_vec); // That printed out the Nones too. Let's filter map them out in a new Vec. let filtered_vec = option_vec.into_iter().filter_map(|c| c).collect::>(); println!(\"And without the Nones: {:?}\", filtered_vec);\n} And here's what this prints: Got a true!\nGot a true!\nNow we have: [Some(\"It\\'s true, you know\"), None, Some(\"It\\'s true, you know\"), None, None]\nAnd without the Nones: [\"It\\'s true, you know\", \"It\\'s true, you know\"]","breadcrumbs":"A tour of the standard library » bool","id":"102","title":"bool"},"103":{"body":"Vec has a lot of methods that we haven't looked at yet. Let's start with .sort(). .sort() is not surprising at all. It uses a &mut self to sort a vector. fn main() { let mut my_vec = vec![100, 90, 80, 0, 0, 0, 0, 0]; my_vec.sort(); println!(\"{:?}\", my_vec);\n} This prints [0, 0, 0, 0, 0, 80, 90, 100]. But there is one more interesting way to sort called .sort_unstable(), and it is usually faster. It can be faster because it doesn't care about the order of numbers if they are the same number. In regular .sort(), you know that the last 0, 0, 0, 0, 0 will be in the same order after .sort(). But .sort_unstable() might move the last zero to index 0, then the third last zero to index 2, etc. .dedup() means \"de-duplicate\". It will remove items that are the same in a vector, but only if they are next to each other. This next code will not just print \"sun\", \"moon\": fn main() { let mut my_vec = vec![\"sun\", \"sun\", \"moon\", \"moon\", \"sun\", \"moon\", \"moon\"]; my_vec.dedup(); println!(\"{:?}\", my_vec);\n} It only gets rid of \"sun\" next to the other \"sun\", then \"moon\" next to one \"moon\", and again with \"moon\" next to another \"moon\". The result is: [\"sun\", \"moon\", \"sun\", \"moon\"]. If you want to remove every duplicate, just .sort() first: fn main() { let mut my_vec = vec![\"sun\", \"sun\", \"moon\", \"moon\", \"sun\", \"moon\", \"moon\"]; my_vec.sort(); my_vec.dedup(); println!(\"{:?}\", my_vec);\n} Result: [\"moon\", \"sun\"].","breadcrumbs":"A tour of the standard library » Vec","id":"103","title":"Vec"},"104":{"body":"You will remember that a String is kind of like a Vec. It is so like a Vec that you can do a lot of the same methods. For example, you can start one with String::with_capacity(). You want that if you are always going to be pushing a char with .push() or pushing a &str with .push_str(). Here's an example of a String that has too many allocations. fn main() { let mut push_string = String::new(); let mut capacity_counter = 0; // capacity starts at 0 for _ in 0..100_000 { // Do this 100,000 times if push_string.capacity() != capacity_counter { // First check if capacity is different now println!(\"{}\", push_string.capacity()); // If it is, print it capacity_counter = push_string.capacity(); // then update the counter } push_string.push_str(\"I'm getting pushed into the string!\"); // and push this in every time }\n} This prints: 35\n70\n140\n280\n560\n1120\n2240\n4480\n8960\n17920\n35840\n71680\n143360\n286720\n573440\n1146880\n2293760\n4587520 We had to reallocate (copy everything over) 18 times. But now we know the final capacity. So we'll give it the capacity right away, and we don't need to reallocate: just one String capacity is enough. fn main() { let mut push_string = String::with_capacity(4587520); // We know the exact number. Some different big number could work too let mut capacity_counter = 0; for _ in 0..100_000 { if push_string.capacity() != capacity_counter { println!(\"{}\", push_string.capacity()); capacity_counter = push_string.capacity(); } push_string.push_str(\"I'm getting pushed into the string!\"); }\n} And this prints 4587520. Perfect! We never had to allocate again. Of course, the actual length is certainly smaller than this. If you try 100,001 times, 101,000 times, etc., it'll still say 4587520. That's because each time the capacity is two times what it was before. We can shrink it though with .shrink_to_fit() (same as for a Vec). Our String is very large and we don't want to add anything more to it, so we can make it a bit smaller. But only do this if you are sure. Here is why: fn main() { let mut push_string = String::with_capacity(4587520); let mut capacity_counter = 0; for _ in 0..100_000 { if push_string.capacity() != capacity_counter { println!(\"{}\", push_string.capacity()); capacity_counter = push_string.capacity(); } push_string.push_str(\"I'm getting pushed into the string!\"); } push_string.shrink_to_fit(); println!(\"{}\", push_string.capacity()); push_string.push('a'); println!(\"{}\", push_string.capacity()); push_string.shrink_to_fit(); println!(\"{}\", push_string.capacity());\n} This prints: 4587520\n3500000\n7000000\n3500001 So first we had a size of 4587520, but we weren't using it all. We used .shrink_to_fit() and got the size down to 3500000. But then we forget that we needed to push an a on. When we did that, Rust saw that we needed more space and gave us double: now it's 7000000. Whoops! So we did .shrink_to_fit() again and now it's back down to 3500001. .pop() works for a String, just like for a Vec. fn main() { let mut my_string = String::from(\".daer ot drah tib elttil a si gnirts sihT\"); loop { let pop_result = my_string.pop(); match pop_result { Some(character) => print!(\"{}\", character), None => break, } }\n} This prints This string is a little bit hard to read. because it starts from the last character. .retain() is a method that uses a closure, which is rare for String. It's just like .filter() for an iterator. fn main() { let mut my_string = String::from(\"Age: 20 Height: 194 Weight: 80\"); my_string.retain(|character| character.is_alphabetic() || character == ' '); // Keep if a letter or a space dbg!(my_string); // Let's use dbg!() for fun this time instead of println!\n} This prints: [src\\main.rs:4] my_string = \"Age Height Weight \"","breadcrumbs":"A tour of the standard library » String","id":"104","title":"String"},"105":{"body":"std::ffi is the part of std that helps you use Rust with other languages or operating systems. It has types like OsString and CString, which are like String for the operating system or String for the language C. They each have their own &str type too: OsStr and CStr. ffi means \"foreign function interface\". You can use OsString when you have to work with an operating system that doesn't have Unicode. All Rust strings are unicode, but not every operating system has it. Here is the simple English explanation from the standard library on why we have OsString: A string on Unix (Linux, etc.) might be lots of bytes together that don't have zeros. And sometimes you read them as Unicode UTF-8. A string on Windows might be made of random 16-bit values that don't have zeros. And sometimes you read them as Unicode UTF-16. In Rust, strings are always valid UTF-8, which may contain zeros. So an OsString is made to be read by all of them. You can do all the regular things with an OsString like OsString::from(\"Write something here\"). It also has an interesting method called .into_string() that tries to make it into a regular String. It returns a Result, but the Err part is just the original OsString: // 🚧\npub fn into_string(self) -> Result So if it doesn't work then you just get it back. You can't call .unwrap() because it will panic, but you can use match to get the OsString back. Let's test it out by calling methods that don't exist. use std::ffi::OsString; fn main() { // ⚠️ let os_string = OsString::from(\"This string works for your OS too.\"); match os_string.into_string() { Ok(valid) => valid.thth(), // Compiler: \"What's .thth()??\" Err(not_valid) => not_valid.occg(), // Compiler: \"What's .occg()??\" }\n} Then the compiler tells us exactly what we want to know: error[E0599]: no method named `thth` found for struct `std::string::String` in the current scope --> src/main.rs:6:28 |\n6 | Ok(valid) => valid.thth(), | ^^^^ method not found in `std::string::String` error[E0599]: no method named `occg` found for struct `std::ffi::OsString` in the current scope --> src/main.rs:7:37 |\n7 | Err(not_valid) => not_valid.occg(), | ^^^^ method not found in `std::ffi::OsString` We can see that the type of valid is String and the type of not_valid is OsString.","breadcrumbs":"A tour of the standard library » OsString and CString","id":"105","title":"OsString and CString"},"106":{"body":"std::mem has some pretty interesting methods. We saw some of them already, such as .size_of(), .size_of_val() and .drop(): use std::mem; fn main() { println!(\"{}\", mem::size_of::()); let my_array = [8; 50]; println!(\"{}\", mem::size_of_val(&my_array)); let mut some_string = String::from(\"You can drop a String because it's on the heap\"); mem::drop(some_string); // some_string.clear(); If we did this it would panic\n} This prints: 4\n200 Here are some other methods in mem: swap(): with this you can change the values between two variables. You use a mutable reference for each to do it. This is helpful when you have two things you want to switch and Rust doesn't let you because of borrowing rules. Or just when you want to quickly switch two things. Here's one example: use std::{mem, fmt}; struct Ring { // Create a ring from Lord of the Rings owner: String, former_owner: String, seeker: String, // seeker means \"person looking for it\"\n} impl Ring { fn new(owner: &str, former_owner: &str, seeker: &str) -> Self { Self { owner: owner.to_string(), former_owner: former_owner.to_string(), seeker: seeker.to_string(), } }\n} impl fmt::Display for Ring { // Display to show who has it and who wants it fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, \"{} has the ring, {} used to have it, and {} wants it\", self.owner, self.former_owner, self.seeker) }\n} fn main() { let mut one_ring = Ring::new(\"Frodo\", \"Gollum\", \"Sauron\"); println!(\"{}\", one_ring); mem::swap(&mut one_ring.owner, &mut one_ring.former_owner); // Gollum got the ring back for a second println!(\"{}\", one_ring);\n} This will print: Frodo has the ring, Gollum used to have it, and Sauron wants it\nGollum has the ring, Frodo used to have it, and Sauron wants it replace(): this is like swap, and actually uses swap inside it, as you can see: pub fn replace(dest: &mut T, mut src: T) -> T { swap(dest, &mut src); src\n} So it just does a swap and then returns the other item. With this you replace the value with something else you put in. And since it returns the old value, so you should use it with let. Here's a quick example. use std::mem; struct City { name: String,\n} impl City { fn change_name(&mut self, name: &str) { let old_name = mem::replace(&mut self.name, name.to_string()); println!( \"The city once called {} is now called {}.\", old_name, self.name ); }\n} fn main() { let mut capital_city = City { name: \"Constantinople\".to_string(), }; capital_city.change_name(\"Istanbul\");\n} This prints The city once called Constantinople is now called Istanbul.. One function called .take() is like .replace() but it leaves the default value in the item. You will remember that default values are usually things like 0, \"\", and so on. Here is the signature: // 🚧\npub fn take(dest: &mut T) -> T\nwhere T: Default, So you can do something like this: use std::mem; fn main() { let mut number_vec = vec![8, 7, 0, 2, 49, 9999]; let mut new_vec = vec![]; number_vec.iter_mut().for_each(|number| { let taker = mem::take(number); new_vec.push(taker); }); println!(\"{:?}\\n{:?}\", number_vec, new_vec);\n} And as you can see, it replaced all the numbers with 0: no index was deleted. [0, 0, 0, 0, 0, 0]\n[8, 7, 0, 2, 49, 9999] Of course, for your own type you can implement Default to whatever you want. Let's look at an example where we have a Bank and a Robber. Every time he robs the Bank, he gets the money at the desk. But the desk can take money from the back any time, so it always has 50. We will make our own type for this so it will always have 50. Here is how it works: use std::mem;\nuse std::ops::{Deref, DerefMut}; // We will use this to get the power of u32 struct Bank { money_inside: u32, money_at_desk: DeskMoney, // This is our \"smart pointer\" type. It has its own default, but it will use u32\n} struct DeskMoney(u32); impl Default for DeskMoney { fn default() -> Self { Self(50) // default is always 50, not 0 }\n} impl Deref for DeskMoney { // With this we can access the u32 using * type Target = u32; fn deref(&self) -> &Self::Target { &self.0 }\n} impl DerefMut for DeskMoney { // And with this we can add, subtract, etc. fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }\n} impl Bank { fn check_money(&self) { println!( \"There is ${} in the back and ${} at the desk.\\n\", self.money_inside, *self.money_at_desk // Use * so we can just print the u32 ); }\n} struct Robber { money_in_pocket: u32,\n} impl Robber { fn check_money(&self) { println!(\"The robber has ${} right now.\\n\", self.money_in_pocket); } fn rob_bank(&mut self, bank: &mut Bank) { let new_money = mem::take(&mut bank.money_at_desk); // Here it takes the money, and leaves 50 because that is the default self.money_in_pocket += *new_money; // Use * because we can only add u32. DeskMoney can't add bank.money_inside -= *new_money; // Same here println!(\"She robbed the bank. She now has ${}!\\n\", self.money_in_pocket); }\n} fn main() { let mut bank_of_klezkavania = Bank { // Set up our bank money_inside: 5000, money_at_desk: DeskMoney(50), }; bank_of_klezkavania.check_money(); let mut robber = Robber { // Set up our robber money_in_pocket: 50, }; robber.check_money(); robber.rob_bank(&mut bank_of_klezkavania); // Rob, then check money robber.check_money(); bank_of_klezkavania.check_money(); robber.rob_bank(&mut bank_of_klezkavania); // Do it again robber.check_money(); bank_of_klezkavania.check_money(); } This will print: There is $5000 in the back and $50 at the desk. The robber has $50 right now. She robbed the bank. She now has $100! The robber has $100 right now. There is $4950 in the back and $50 at the desk. She robbed the bank. She now has $150! The robber has $150 right now. There is $4900 in the back and $50 at the desk. You can see that there is always $50 at the desk.","breadcrumbs":"A tour of the standard library » mem","id":"106","title":"mem"},"107":{"body":"The standard library has a prelude too, which is why you don't have to write things like use std::vec::Vec to create a Vec. You can see all the items here , and will already know almost all of them: std::marker::{Copy, Send, Sized, Sync, Unpin}. You haven't seen Unpin before, because it is used for almost every type (like Sized, which is also very common). To \"pin\" means to not let something move. In this case a Pin means that it can't move in memory, but most items have Unpin so you can. That's why functions like std::mem::replace work, because they aren't pinned. std::ops::{Drop, Fn, FnMut, FnOnce}. std::mem::drop std::boxed::Box. std::borrow::ToOwned. You saw this before a bit with Cow, which can take borrowed content and make it owned. It uses .to_owned() to do this. You can also use .to_owned() on a &str to get a String, and the same for other borrowed values. std::clone::Clone std::cmp::{PartialEq, PartialOrd, Eq, Ord}. std::convert::{AsRef, AsMut, Into, From}. std::default::Default. std::iter::{Iterator, Extend, IntoIterator, DoubleEndedIterator, ExactSizeIterator}. We used .rev() for an iterator before: this actually makes a DoubleEndedIterator. An ExactSizeIterator is just something like 0..10: it already knows that it has a .len() of 10. Other iterators don't know their length for sure. std::option::Option::{self, Some, None}. std::result::Result::{self, Ok, Err}. std::string::{String, ToString}. std::vec::Vec. What if you don't want the prelude for some reason? Just add the attribute #![no_implicit_prelude]. Let's give it a try and watch the compiler complain: // ⚠️\n#![no_implicit_prelude]\nfn main() { let my_vec = vec![8, 9, 10]; let my_string = String::from(\"This won't work\"); println!(\"{:?}, {}\", my_vec, my_string);\n} Now Rust has no idea what you are trying to do: error: cannot find macro `println` in this scope --> src/main.rs:5:5 |\n5 | println!(\"{:?}, {}\", my_vec, my_string); | ^^^^^^^ error: cannot find macro `vec` in this scope --> src/main.rs:3:18 |\n3 | let my_vec = vec![8, 9, 10]; | ^^^ error[E0433]: failed to resolve: use of undeclared type or module `String` --> src/main.rs:4:21 |\n4 | let my_string = String::from(\"This won't work\"); | ^^^^^^ use of undeclared type or module `String` error: aborting due to 3 previous errors So for this simple code you need to tell Rust to use the extern (external) crate called std, and then the items you want. Here is everything we have to do just to create a Vec and a String and print it: #![no_implicit_prelude] extern crate std; // Now you have to tell Rust that you want to use a crate called std\nuse std::vec; // We need the vec macro\nuse std::string::String; // and string\nuse std::convert::From; // and this to convert from a &str to the String\nuse std::println; // and this to print fn main() { let my_vec = vec![8, 9, 10]; let my_string = String::from(\"This won't work\"); println!(\"{:?}, {}\", my_vec, my_string);\n} And now it finally works, printing [8, 9, 10], This won't work. So you can see why Rust uses the prelude. But if you want, you don't need to use it. And you can even use #![no_std] (we saw this once) for when you can't even use something like stack memory. But most of the time you don't have to think about not using the prelude or std at all. So why didn't we see the extern keyword before? It's because you don't need it that much anymore. Before, when bringing in an external crate you had to use it. So to use rand in the past, you had to write: extern crate rand; and then use statements for the mods, traits, etc. that you wanted to use. But the Rust compiler now doesn't need this help anymore - you can just use use and it knows where to find it. So you almost never need extern crate anymore, but in other people's Rust code you might still see it on the top.","breadcrumbs":"A tour of the standard library » prelude","id":"107","title":"prelude"},"108":{"body":"std::time is where you can get functions for time. (If you want even more functions, a crate like chrono can work.) The simplest function is just getting the system time with Instant::now(). use std::time::Instant; fn main() { let time = Instant::now(); println!(\"{:?}\", time);\n} If you print it, you'll get something like this: Instant { tv_sec: 2738771, tv_nsec: 685628140 }. That's talking about seconds and nanoseconds, but it's not very useful. If you look at 2738771 seconds for example (written in August), it is 31.70 days. That doesn't have anything to do with the month or the day of the year. But the page on Instant tells us that it isn't supposed to be useful on its own. It says that it is \"opaque and useful only with Duration.\" Opaque means \"you can't figure it out\", and duration means \"how much time passed\". So it's only useful when doing things like comparing times. If you look at the traits on the left, one of them is Sub. That means we can use - to subtract one from another. And when we click on [src] to see what it does, it says: impl Sub for Instant { type Output = Duration; fn sub(self, other: Instant) -> Duration { self.duration_since(other) }\n} So it takes an Instant and uses .duration_since() to give a Duration. Let's try printing that. We'll make two Instant::now()s right next to each other, then we'll make the program busy for a while. Then we'll make one more Instant::now(). Finally, we'll see how long it took. use std::time::Instant; fn main() { let time1 = Instant::now(); let time2 = Instant::now(); // These two are right next to each other let mut new_string = String::new(); loop { new_string.push('წ'); // Make Rust push this Georgian letter onto the String if new_string.len() > 100_000 { // until it is 100,000 bytes long break; } } let time3 = Instant::now(); println!(\"{:?}\", time2 - time1); println!(\"{:?}\", time3 - time1);\n} This will print something like this: 1.025µs\n683.378µs So that's just over 1 microsecond vs. 683 microseconds. We can see that Rust did take some time to do it. There is one fun thing we can do with just a single Instant though. We can turn it into a String with format!(\"{:?}\", Instant::now());. It looks like this: use std::time::Instant; fn main() { let time1 = format!(\"{:?}\", Instant::now()); println!(\"{}\", time1);\n} That prints something like Instant { tv_sec: 2740773, tv_nsec: 632821036 }. That's not useful, but if we use .iter() and .rev() and .skip(2), we can skip the } and at the end. We can use it to make a random number generator. use std::time::Instant; fn bad_random_number(digits: usize) { if digits > 9 { panic!(\"Random number can only be up to 9 digits\"); } let now = Instant::now(); let output = format!(\"{:?}\", now); output .chars() .rev() .skip(2) .take(digits) .for_each(|character| print!(\"{}\", character)); println!();\n} fn main() { bad_random_number(1); bad_random_number(1); bad_random_number(3); bad_random_number(3);\n} This will print something like: 6\n4\n967\n180 The function is called bad_random_number because it's not a very good random number generator. Rust has better crates that make random numbers with less code than rand like fastrand. But it's a good example of how you can use your imagination to do something with Instant. When you have a thread, you can use std::thread::sleep to make it stop for a while. When you do this, you have to give it a duration. You don't have to make more than one thread to do this because every program is on at least one thread. sleep needs a Duration though, so it can know how long to sleep. You can pick the unit like this: Duration::from_millis(), Duration::from_secs, etc. Here's one example: use std::time::Duration;\nuse std::thread::sleep; fn main() { let three_seconds = Duration::from_secs(3); println!(\"I must sleep now.\"); sleep(three_seconds); println!(\"Did I miss anything?\");\n} This will just print I must sleep now.\nDid I miss anything? but the thread will do nothing for three seconds. You usually use .sleep() when you have many threads that need to try something a lot, like connecting. You don't want the thread to use your processor to try 100,000 times in a second when you just want it to check sometimes. So then you can set a Duration, and it will try to do its task every time it wakes up.","breadcrumbs":"A tour of the standard library » time","id":"108","title":"time"},"109":{"body":"Let's take a look at some other macros. unreachable!() This macro is kind of like todo!() except it's for code that you will never do. Maybe you have a match in an enum that you know will never choose one of the arms, so the code can never be reached. If that's so, you can write unreachable!() so the compiler knows that it can ignore that part. For example, let's say you have a program that writes something when you choose a place to live in. They are in Ukraine, and all of them are nice except Chernobyl. Your program doesn't let anyone choose Chernobyl, because it's not a good place to live right now. But the enum was made a long time ago in someone else's code, and you can't change it. So in the match arm you can use the macro here. It looks like this: enum UkrainePlaces { Kiev, Kharkiv, Chernobyl, // Pretend we can't change the enum - Chernobyl will always be here Odesa, Dnipro,\n} fn choose_city(place: &UkrainePlaces) { use UkrainePlaces::*; match place { Kiev => println!(\"You will live in Kiev\"), Kharkiv => println!(\"You will live in Kharkiv\"), Chernobyl => unreachable!(), Odesa => println!(\"You will live in Odesa\"), Dnipro => println!(\"You will live in Dnipro\"), }\n} fn main() { let user_input = UkrainePlaces::Kiev; // Pretend the user input is made from some other function. The user can't choose Chernobyl, no matter what choose_city(&user_input);\n} This will print You will live in Kiev. unreachable!() is also nice for you to read because it reminds you that some part of the code is unreachable. You have to be sure that the code is actually unreachable though. If the compiler ever calls unreachable!(), the program will panic. Also, if you ever have unreachable code that the compiler knows about, it will tell you. Here is a quick example: fn main() { let true_or_false = true; match true_or_false { true => println!(\"It's true\"), false => println!(\"It's false\"), true => println!(\"It's true\"), // Whoops, we wrote true again }\n} It will say: warning: unreachable pattern --> src/main.rs:7:9 |\n7 | true => println!(\"It's true\"), | ^^^^ | But unreachable!() is for when the compiler can't know, like our other example. column!, line!, file!, module_path! These four macros are kind of like dbg!() because you just put them in to give you debug information. But they don't take any variables - you just use them with the brackets and nothing else. They are easy to learn together: column!() gives you the column where you wrote it, file!() gives you the name of the file where you wrote it, line!() gives you the line where you wrote it, and module_path!() gives you the module where it is. The next code shows all three in a simple example. We will pretend there is a lot more code (mods inside mods), because that is why we would want to use these macros. You can imagine a big Rust program over many mods and files. pub mod something { pub mod third_mod { pub fn print_a_country(input: &mut Vec<&str>) { println!( \"The last country is {} inside the module {}\", input.pop().unwrap(), module_path!() ); } }\n} fn main() { use something::third_mod::*; let mut country_vec = vec![\"Portugal\", \"Czechia\", \"Finland\"]; // do some stuff println!(\"Hello from file {}\", file!()); // do some stuff println!( \"On line {} we got the country {}\", line!(), country_vec.pop().unwrap() ); // do some more stuff println!( \"The next country is {} on line {} and column {}.\", country_vec.pop().unwrap(), line!(), column!(), ); // lots more code print_a_country(&mut country_vec);\n} It prints this: Hello from file src/main.rs\nOn line 23 we got the country Finland\nThe next country is Czechia on line 32 and column 9.\nThe last country is Portugal inside the module rust_book::something::third_mod cfg! We know that you can use attributes like #[cfg(test)] and #[cfg(windows)] to tell the compiler what to do in certain cases. When you have test, it will run the code when you run Rust under testing mode (if it's on your computer you type cargo test). And when you use windows, it will run the code if the user is using Windows. But maybe you just want to change one tiny bit of code depending on the operating system, etc. That's when this macro is useful. It returns a bool. fn main() { let helpful_message = if cfg!(target_os = \"windows\") { \"backslash\" } else { \"slash\" }; println!( \"...then in your hard drive, type the directory name followed by a {}. Then you...\", helpful_message );\n} This will print differently, depending on your system. The Rust Playground runs on Linux, so it will print: ...then in your hard drive, type the directory name followed by a slash. Then you... cfg!() works for any kind of configuration. Here is an example of a function that runs differently when you use it inside a test. #[cfg(test)] // cfg! will know to look for the word test\nmod testing { use super::*; #[test] fn check_if_five() { assert_eq!(bring_number(true), 5); // This bring_number() function should return 5 }\n} fn bring_number(should_run: bool) -> u32 { // This function takes a bool as to whether it should run if cfg!(test) && should_run { // if it should run and has the configuration test, return 5 5 } else if should_run { // if it's not a test but it should run, print something. When you run a test it ignores println! statements println!(\"Returning 5. This is not a test\"); 5 } else { println!(\"This shouldn't run, returning 0.\"); // otherwise return 0 0 }\n} fn main() { bring_number(true); bring_number(false);\n} Now it will run differently depending on the configuration. If you just run the program, it will give you this: Returning 5. This is not a test\nThis shouldn't run, returning 0. But if you run it in test mode (cargo test for Rust on your computer), it will actually run the test. And because the test always returns 5 in this case, it will pass. running 1 test\ntest testing::check_if_five ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out","breadcrumbs":"A tour of the standard library » Other macros","id":"109","title":"Other macros"},"11":{"body":"Floats are numbers with decimal points. 5.5 is a float, and 6 is an integer. 5.0 is also a float, and even 5. is a float. fn main() { let my_float = 5.; // Rust sees . and knows that it is a float\n} But the types are not called float, they are called f32 and f64. It is the same as integers: the number after f shows the number of bits. If you don't write the type, Rust will choose f64. Of course, only floats of the same type can be used together. So you can't add an f32 to an f64. fn main() { let my_float: f64 = 5.0; // This is an f64 let my_other_float: f32 = 8.5; // This is an f32 let third_float = my_float + my_other_float; // ⚠️\n} When you try to run this, Rust will say: error[E0308]: mismatched types --> src\\main.rs:5:34 |\n5 | let third_float = my_float + my_other_float; | ^^^^^^^^^^^^^^ expected `f64`, found `f32` The compiler writes \"expected (type), found (type)\" when you use the wrong type. It reads your code like this: fn main() { let my_float: f64 = 5.0; // The compiler sees an f64 let my_other_float: f32 = 8.5; // The compiler sees an f32. It is a different type. let third_float = my_float + // You want to add my_float to something, so it must be an f64 plus another f64. Now it expects an f64... let third_float = my_float + my_other_float; // ⚠️ but it found an f32. It can't add them.\n} So when you see \"expected (type), found (type)\", you must find why the compiler expected a different type. Of course, with simple numbers it is easy to fix. You can cast the f32 to an f64 with as: fn main() { let my_float: f64 = 5.0; let my_other_float: f32 = 8.5; let third_float = my_float + my_other_float as f64; // my_other_float as f64 = use my_other_float like an f64\n} Or even more simply, remove the type declarations. (\"to declare a type\" = \"to tell Rust to use the type\") Rust will choose types that can add together. fn main() { let my_float = 5.0; // Rust will choose f64 let my_other_float = 8.5; // Here again it will choose f64 let third_float = my_float + my_other_float;\n} The Rust compiler is smart and will not choose f64 if you need f32: fn main() { let my_float: f32 = 5.0; let my_other_float = 8.5; // Usually Rust would choose f64, let third_float = my_float + my_other_float; // but now it knows that you need to add it to an f32. So it chooses f32 for my_other_float too\n}","breadcrumbs":"Type inference » Floats","id":"11","title":"Floats"},"110":{"body":"Writing macros can be very complicated. You almost never need to write one, but sometimes you might want to because they are very convenient. Writing macros is interesting because they are almost a different language. To write one, you actually use another macro called macro_rules!. Then you add your macro name and open a {} block. Inside is sort of like a match statement. Here's one that only takes (), then just returns 6: macro_rules! give_six { () => { 6 };\n} fn main() { let six = give_six!(); println!(\"{}\", six);\n} But it's not the same as a match statement, because a macro actually doesn't compile anything. It just takes an input and gives an output. Then the compiler checks to see if it makes sense. That's why a macro is like \"code that writes code\". You will remember that a true match statement needs to give the same type, so this won't work: fn main() {\n// ⚠️ let my_number = 10; match my_number { 10 => println!(\"You got a ten\"), _ => 10, }\n} It will complain that you want to return () in one case, and i32 in the other. error[E0308]: `match` arms have incompatible types --> src\\main.rs:5:14 |\n3 | / match my_number {\n4 | | 10 => println!(\"You got a ten\"), | | ------------------------- this is found to be of type `()`\n5 | | _ => 10, | | ^^ expected `()`, found integer\n6 | | } | |_____- `match` arms have incompatible types But a macro doesn't care, because it's just giving an output. It's not a compiler - it's code before code. So you can do this: macro_rules! six_or_print { (6) => { 6 }; () => { println!(\"You didn't give me 6.\"); };\n} fn main() { let my_number = six_or_print!(6); six_or_print!();\n} This is just fine, and prints You didn't give me 6.. You can also see that it's not a match arm because there's no _ case. We can only give it (6), or (). Anything else will make an error. And the 6 we give it isn't even an i32, it's just an input 6. You can actually set anything as the input for a macro, because it's just looking at input to see what it gets. For example: macro_rules! might_print { (THis is strange input 하하はは哈哈 but it still works) => { println!(\"You guessed the secret message!\") }; () => { println!(\"You didn't guess it\"); };\n} fn main() { might_print!(THis is strange input 하하はは哈哈 but it still works); might_print!();\n} So this strange macro only responds to two things: () and (THis is strange input 하하はは哈哈 but it still works). Nothing else. It prints: You guessed the secret message!\nYou didn't guess it So a macro isn't exactly Rust syntax. But a macro can also understand different types of input that you give it. Take this example: macro_rules! might_print { ($input:expr) => { println!(\"You gave me: {}\", $input); }\n} fn main() { might_print!(6);\n} This will print You gave me: 6. The $input:expr part is important. It means \"for an expression, give it the variable name $input\". In macros, variables start with a $. In this macro, if you give it one expression, it will print it. Let's try it out some more: macro_rules! might_print { ($input:expr) => { println!(\"You gave me: {:?}\", $input); // Now we'll use {:?} because we will give it different kinds of expressions }\n} fn main() { might_print!(()); // give it a () might_print!(6); // give it a 6 might_print!(vec![8, 9, 7, 10]); // give it a vec\n} This will print: You gave me: ()\nYou gave me: 6\nYou gave me: [8, 9, 7, 10] Also note that we wrote {:?}, but it won't check to see if &input implements Debug. It'll just write the code and try to make it compile, and if it doesn't then it gives an error. So what can a macro see besides expr? They are: block | expr | ident | item | lifetime | literal | meta | pat | path | stmt | tt | ty | vis. This is the complicated part. You can see what each of them means here , where it says: item: an Item\nblock: a BlockExpression\nstmt: a Statement without the trailing semicolon (except for item statements that require semicolons)\npat: a Pattern\nexpr: an Expression\nty: a Type\nident: an IDENTIFIER_OR_KEYWORD\npath: a TypePath style path\ntt: a TokenTree (a single token or tokens in matching delimiters (), [], or {})\nmeta: an Attr, the contents of an attribute\nlifetime: a LIFETIME_TOKEN\nvis: a possibly empty Visibility qualifier\nliteral: matches -?LiteralExpression There is another good site called cheats.rs that explains them here and gives examples for each. However, for most macros you will use expr, ident, and tt. ident means identifier and is for variable or function names. tt means token tree and sort of means any type of input. Let's try a simple macro with both. macro_rules! check { ($input1:ident, $input2:expr) => { println!( \"Is {:?} equal to {:?}? {:?}\", $input1, $input2, $input1 == $input2 ); };\n} fn main() { let x = 6; let my_vec = vec![7, 8, 9]; check!(x, 6); check!(my_vec, vec![7, 8, 9]); check!(x, 10);\n} So this will take one ident (like a variable name) and an expression and see if they are the same. It prints: Is 6 equal to 6? true\nIs [7, 8, 9] equal to [7, 8, 9]? true\nIs 6 equal to 10? false And here's one macro that takes a tt and prints it. It uses a macro called stringify! to make a string first. macro_rules! print_anything { ($input:tt) => { let output = stringify!($input); println!(\"{}\", output); };\n} fn main() { print_anything!(ththdoetd); print_anything!(87575oehq75onth);\n} This prints: ththdoetd\n87575oehq75onth But it won't print if we give it something with spaces, commas, etc. It will think that we are giving it more than one item or extra information, so it will be confused. This is where macros start to get difficult. To give a macro more than one item at a time, we have to use a different syntax. Instead of $input, it will be $($input1),*. This means zero or more (this is what * means), separated by a comma. If you want one or more, use + instead of *. Now our macro looks like this: macro_rules! print_anything { ($($input1:tt),*) => { let output = stringify!($($input1),*); println!(\"{}\", output); };\n} fn main() { print_anything!(ththdoetd, rcofe); print_anything!(); print_anything!(87575oehq75onth, ntohe, 987987o, 097);\n} So it takes any token tree separated by commas, and uses stringify! to make it into a string. Then it prints it. It prints: ththdoetd, rcofe 87575oehq75onth, ntohe, 987987o, 097 If we used + instead of * it would give an error, because one time we gave it no input. So * is a bit safer option. So now we can start to see the power of macros. In this next example we can actually make our own functions: macro_rules! make_a_function { ($name:ident, $($input:tt),*) => { // First you give it one name for the function, then it checks everything else fn $name() { let output = stringify!($($input),*); // It makes everything else into a string println!(\"{}\", output); } };\n} fn main() { make_a_function!(print_it, 5, 5, 6, I); // We want a function called print_it() that prints everything else we give it print_it(); make_a_function!(say_its_nice, this, is, really, nice); // Same here but we change the function name say_its_nice();\n} This prints: 5, 5, 6, I\nthis, is, really, nice So now we can start to understand other macros. You can see that some of the macros we've already been using are pretty simple. Here's the one for write! that we used to write to files: macro_rules! write { ($dst:expr, $($arg:tt)*) => ($dst.write_fmt($crate::format_args!($($arg)*)))\n} So to use it, you enter this: an expression (expr) that gets the variable name $dst. everything after that. If it wrote $arg:tt then it would only take one, but because it wrote $($arg:tt)* it takes zero, one, or any number. Then it takes $dst and uses a method called write_fmt on it. Inside that, it uses another macro called format_args! that takes all $($arg)*, or all the arguments we put in. Now let's take a look at the todo! macro. That's the one you use when you want the program to compile but haven't written your code yet. It looks like this: macro_rules! todo { () => (panic!(\"not yet implemented\")); ($($arg:tt)+) => (panic!(\"not yet implemented: {}\", $crate::format_args!($($arg)+)));\n} This one has two options: you can enter (), or a number of token trees (tt). If you enter (), it just uses panic! with a message. So you could actually just write panic!(\"not yet implemented\") instead of todo! and it would be the same. If you enter some arguments, it will try to print them. You can see the same format_args! macro inside, which works like println!. So if you write this, it will work too: fn not_done() { let time = 8; let reason = \"lack of time\"; todo!(\"Not done yet because of {}. Check back in {} hours\", reason, time);\n} fn main() { not_done();\n} This will print: thread 'main' panicked at 'not yet implemented: Not done yet because of lack of time. Check back in 8 hours', src/main.rs:4:5 Inside a macro you can even call the same macro. Here's one: macro_rules! my_macro { () => { println!(\"Let's print this.\"); }; ($input:expr) => { my_macro!(); }; ($($input:expr),*) => { my_macro!(); }\n} fn main() { my_macro!(vec![8, 9, 0]); my_macro!(toheteh); my_macro!(8, 7, 0, 10); my_macro!();\n} This one takes either (), or one expression, or many expressions. But it ignores all the expressions no matter what you put in, and just calls my_macro! on (). So the output is just Let's print this, four times. You can see the same thing in the dbg! macro, which also calls itself. macro_rules! dbg { () => { $crate::eprintln!(\"[{}:{}]\", $crate::file!(), $crate::line!()); //$crate means the crate that it's in. }; ($val:expr) => { // Use of `match` here is intentional because it affects the lifetimes // of temporaries - https://stackoverflow.com/a/48732525/1063961 match $val { tmp => { $crate::eprintln!(\"[{}:{}] {} = {:#?}\", $crate::file!(), $crate::line!(), $crate::stringify!($val), &tmp); tmp } } }; // Trailing comma with single argument is ignored ($val:expr,) => { $crate::dbg!($val) }; ($($val:expr),+ $(,)?) => { ($($crate::dbg!($val)),+,) };\n} (eprintln! is the same as println! except it prints to io::stderr instead of io::stdout. There is also eprint! that doesn't add a new line) So we can try this out ourself. fn main() { dbg!();\n} That matches the first arm, so it will print the file name and line name with the file! and line! macros. It prints [src/main.rs:2]. Let's try it with this: fn main() { dbg!(vec![8, 9, 10]);\n} This will match the next arm, because it's one expression. It will then call the input tmp and use this code: $crate::eprintln!(\"[{}:{}] {} = {:#?}\", $crate::file!(), $crate::line!(), $crate::stringify!($val), &tmp);. So it will print with file! and line!, then $val made into a String, and pretty print with {:#?} for tmp. So for our input it will write this: [src/main.rs:2] vec![8, 9, 10] = [ 8, 9, 10,\n] And for the rest of it it just calls dbg! on itself even if you put in an extra comma. As you can see, macros are very complicated! Usually you only want a macro to automatically do something that a simple function can't do very well. The best way to learn about macros is to look at other macro examples. Not many people can quickly write macros without problems. So don't think that you need to know everything about macros to know how to write in Rust. But if you read other macros, and change them a little, you can easily borrow their power. Then you might start to get comfortable with writing your own.","breadcrumbs":"Writing macros » Writing macros","id":"110","title":"Writing macros"},"111":{"body":"You saw that we can learn almost anything in Rust just using the Playground. But if you learned everything so far, you will probably want Rust on your computer now. There are always things that you can't do with the Playground like using files or code in more than just one file. Some other things you need Rust on your computer for are input and flags. But most important is that with Rust on your computer you can use crates. We already learned about crates, but in the Playground you could only use the most popular ones. But with Rust on your computer you can use any crate in your program.","breadcrumbs":"Writing macros » Part 2 - Rust on your computer","id":"111","title":"Part 2 - Rust on your computer"},"112":{"body":"rustc means Rust compiler, and it's what does the actual compiling. A rust file ends with an .rs. But most people don't write something like rustc main.rs to compile. They use something called cargo, which is the main package manager for Rust. One note about the name: it's called cargo because when you put crates together, you get cargo. A crate is a wooden box that you see on ships or trucks, but you remember that every Rust project is also called a crate. Then when you put them together you get the whole cargo. You can see this when you use cargo to run a project. Let's try something simple with rand: we'll just randomly choose between eight letters. use rand::seq::SliceRandom; // Use this for .choose over slices fn main() { let my_letters = vec!['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']; let mut rng = rand::thread_rng(); for _ in 0..6 { print!(\"{} \", my_letters.choose(&mut rng).unwrap()); }\n} This will print something like b c g h e a. But we want to see what cargo does first. To use cargo and run our program, usually we type cargo run. This will build our program and run it for us. But when it starts compiling, it does something like this: Compiling getrandom v0.1.14 Compiling cfg-if v0.1.10 Compiling ppv-lite86 v0.2.8 Compiling rand_core v0.5.1 Compiling rand_chacha v0.2.2 Compiling rand v0.7.3 Compiling rust_book v0.1.0 (C:\\Users\\mithr\\OneDrive\\Documents\\Rust\\rust_book) Finished dev [unoptimized + debuginfo] target(s) in 13.13s Running `C:\\Users\\mithr\\OneDrive\\Documents\\Rust\\rust_book\\target\\debug\\rust_book.exe`\ng f c f h b So it looks like it didn't just bring in rand, but some others too. That's because we need rand for our crate, but rand also has some code that needs other crates too. So cargo will find all the crates we need and put them together. In our case we only had seven, but on very big projects you may have 200 or more crates to bring in. This is where you can see the tradeoff for Rust. Rust is extremely fast, because it compiles ahead of time. It does this by looking through the code and looking to see what the code you write actually does. For example, you might write this generic code: use std::fmt::Display; fn print_and_return_thing(input: T) -> T { println!(\"You gave me {} and now I will give it back.\", input); input\n} fn main() { let my_name = print_and_return_thing(\"Windy\"); let small_number = print_and_return_thing(9.0);\n} This function can take anything with Display, so we gave it a &str and next gave it a f64 and that is no problem for us. But the compiler doesn't look at generics, because it doesn't want to do anything at runtime. It wants to put together a program that can run by itself as fast as possible. So when it looks at the first part with \"Windy\", it doesn't see fn print_and_return_thing(input: T) -> T. It sees something like fn print_and_return_thing(input: &str) -> &str. And next it sees fn print_and_return_thing(input: f64) -> f64. All the checking about traits and so on is done during compile time. That's why generics take longer to compile, because it needs to figure them out, and make it concrete. One more thing: Rust in 2020 is working hard on compile time, because this part takes the longest. Every version of Rust is a little bit faster at compiling, and there are some other plans to speed it up. But in the meantime, here's what you should know: cargo build will build your program so you can run it cargo run will build your program and run it cargo build --release and cargo run --release will do the same but in release mode. What's that? Release mode is for when your code is finally done. Then Rust will take even longer to compile, but it does this because it uses everything it knows to make it faster. Release mode is actually a lot faster than the regular mode, which is called debug mode. That's because it compiles quicker and has more debug information. The regular cargo build is called a \"debug build\" and cargo build --release is called a \"release build\". cargo check is a way to check your code. It's like compiling except that it won't actually make your program. This is a good way to check your code a lot because it doesn't take as long as build or run. By the way, the --release part of the command is called a flag. That means extra information in a command. Some other things you need to know are: cargo new. You do this to create a new Rust project. After new, write the name of the project and cargo will make the folder and all the files you need. cargo clean. When you add crates to Cargo.toml, the computer will download all the files it needs and they can take a lot of space. If you don't want them on your computer anymore, type cargo clean. One more thing about the compiler: it only takes the most time when you use cargo build or cargo run the first time. After that it will remember, and it will compile fast again. But if you use cargo clean and then run cargo build, it will have to compile slowly one more time.","breadcrumbs":"cargo » cargo","id":"112","title":"cargo"},"113":{"body":"One easy way to take input from the user is with std::io::stdin. This means \"standard in\", which is the input from the keyboard. With stdin() you can get user input, but then you will want to put it in a &mut String with .read_line(). Here is a simple example of that, but it both works and doesn't work: use std::io; fn main() { println!(\"Please type something, or x to escape:\"); let mut input_string = String::new(); while input_string != \"x\" { // This is the part that doesn't work right input_string.clear(); // First clear the String. Otherwise it will keep adding to it io::stdin().read_line(&mut input_string).unwrap(); // Get the stdin from the user, and put it in read_string println!(\"You wrote {}\", input_string); } println!(\"See you later!\");\n} Here is what an output output looks like: Please type something, or x to escape:\nsomething\nYou wrote something Something else\nYou wrote Something else x\nYou wrote x x\nYou wrote x x\nYou wrote x It takes our input and gives it back, and it even knows that we typed x. But it doesn't exit the program. The only way to get out is to close the window, or type ctrl and c. Let's change the {} to {:?} in println! to get more information (or you could use dbg!(&input_string) if you like that macro). Now it says: Please type something, or x to escape:\nsomething\nYou wrote \"something\\r\\n\"\nSomething else\nYou wrote \"Something else\\r\\n\"\nx\nYou wrote \"x\\r\\n\"\nx\nYou wrote \"x\\r\\n\" This is because the keyboard input is actually not just something, it is something and the Enter key. There is an easy method to fix this called .trim(), which removes all the whitespace. Whitespace, by the way, is all these characters : U+0009 (horizontal tab, '\\t')\nU+000A (line feed, '\\n')\nU+000B (vertical tab)\nU+000C (form feed)\nU+000D (carriage return, '\\r')\nU+0020 (space, ' ')\nU+0085 (next line)\nU+200E (left-to-right mark)\nU+200F (right-to-left mark)\nU+2028 (line separator)\nU+2029 (paragraph separator) So that will turn x\\r\\n into just x. Now it works: use std::io; fn main() { println!(\"Please type something, or x to escape:\"); let mut input_string = String::new(); while input_string.trim() != \"x\" { input_string.clear(); io::stdin().read_line(&mut input_string).unwrap(); println!(\"You wrote {}\", input_string); } println!(\"See you later!\");\n} Now it will print: Please type something, or x to escape:\nsomething\nYou wrote something Something\nYou wrote Something x\nYou wrote x See you later! There is another kind of user input called std::env::Args (env means environment). Args is what the user types when starting the program. There is actually always at least one Arg in a program. Let's write a program that only prints them using std::env::args() to see what they are. fn main() { println!(\"{:?}\", std::env::args());\n} If we write cargo run then it prints something like this: Args { inner: [\"target\\\\debug\\\\rust_book.exe\"] } Let's give it more input and see what it does. We'll type cargo run but with some extra words. It gives us: Args { inner: [\"target\\\\debug\\\\rust_book.exe\", \"but\", \"with\", \"some\", \"extra\", \"words\"] } Interesting. And when we look at the page for Args , we see that it implements IntoIterator. That means we can do all the things we know about iterators to read and change it. Let's try this: use std::env::args; fn main() { let input = args(); for entry in input { println!(\"You entered: {}\", entry); }\n} Now it says: You entered: target\\debug\\rust_book.exe\nYou entered: but\nYou entered: with\nYou entered: some\nYou entered: extra\nYou entered: words You can see that the first argument is always the program name, so you will often want to skip it, like this: use std::env::args; fn main() { let input = args(); input.skip(1).for_each(|item| { println!(\"You wrote {}, which in capital letters is {}\", item, item.to_uppercase()); })\n} That will print: You wrote but, which in capital letters is BUT\nYou wrote with, which in capital letters is WITH\nYou wrote some, which in capital letters is SOME\nYou wrote extra, which in capital letters is EXTRA\nYou wrote words, which in capital letters is WORDS One common use for Args is for user settings. You can make sure that the user writes the input you need, and only run the program if it's right. Here's a small program that either makes letters big (capital) or small (lowercase): use std::env::args; enum Letters { Capitalize, Lowercase, Nothing,\n} fn main() { let mut changes = Letters::Nothing; let input = args().collect::>(); if input.len() > 2 { match input[1].as_str() { \"capital\" => changes = Letters::Capitalize, \"lowercase\" => changes = Letters::Lowercase, _ => {} } } for word in input.iter().skip(2) { match changes { Letters::Capitalize => println!(\"{}\", word.to_uppercase()), Letters::Lowercase => println!(\"{}\", word.to_lowercase()), _ => println!(\"{}\", word) } } } Here are some examples of what it gives: Input: cargo run please make capitals: make capitals Input: cargo run capital: // Nothing here... Input: cargo run capital I think I understand now: I\nTHINK\nI\nUNDERSTAND\nNOW Input: cargo run LOWERCASE Does this work too? does\nthis\nwork\ntoo? Besides Args given by the user, available in std::env::args(), there are also Vars which are the system variables. Those are the basic settings for the program that the user didn't type in. You can use std::env::vars() to see them all as a (String, String). There are very many. For example: fn main() { for item in std::env::vars() { println!(\"{:?}\", item); }\n} Just doing this shows you all the information about your user session. It will show information like this: (\"CARGO\", \"/playground/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/cargo\")\n(\"CARGO_HOME\", \"/playground/.cargo\")\n(\"CARGO_MANIFEST_DIR\", \"/playground\")\n(\"CARGO_PKG_AUTHORS\", \"The Rust Playground\")\n(\"CARGO_PKG_DESCRIPTION\", \"\")\n(\"CARGO_PKG_HOMEPAGE\", \"\")\n(\"CARGO_PKG_NAME\", \"playground\")\n(\"CARGO_PKG_REPOSITORY\", \"\")\n(\"CARGO_PKG_VERSION\", \"0.0.1\")\n(\"CARGO_PKG_VERSION_MAJOR\", \"0\")\n(\"CARGO_PKG_VERSION_MINOR\", \"0\")\n(\"CARGO_PKG_VERSION_PATCH\", \"1\")\n(\"CARGO_PKG_VERSION_PRE\", \"\")\n(\"DEBIAN_FRONTEND\", \"noninteractive\")\n(\"HOME\", \"/playground\")\n(\"HOSTNAME\", \"f94c15b8134b\")\n(\"LD_LIBRARY_PATH\", \"/playground/target/debug/build/backtrace-sys-3ec4c973f371c302/out:/playground/target/debug/build/libsqlite3-sys-fbddfbb9b241dacb/out:/playground/target/debug/build/ring-cadba5e583648abb/out:/playground/target/debug/deps:/playground/target/debug:/playground/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib:/playground/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib\")\n(\"PATH\", \"/playground/.cargo/bin:/playground/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\")\n(\"PLAYGROUND_EDITION\", \"2018\")\n(\"PLAYGROUND_TIMEOUT\", \"10\")\n(\"PWD\", \"/playground\")\n(\"RUSTUP_HOME\", \"/playground/.rustup\")\n(\"RUSTUP_TOOLCHAIN\", \"stable-x86_64-unknown-linux-gnu\")\n(\"RUST_RECURSION_COUNT\", \"1\")\n(\"SHLVL\", \"1\")\n(\"SSL_CERT_DIR\", \"/usr/lib/ssl/certs\")\n(\"SSL_CERT_FILE\", \"/usr/lib/ssl/certs/ca-certificates.crt\")\n(\"USER\", \"playground\")\n(\"_\", \"/usr/bin/timeout\") So if you need this information, Vars is what you want. The easiest way to get a single Var is by using the env! macro. You just give it the name of the variable, and it will give you a &str with the value. It won't work if the variable is spelled wrong or does not exist, so if you aren't sure then use option_env! instead. If we write this on the Playground: fn main() { println!(\"{}\", env!(\"USER\")); println!(\"{}\", option_env!(\"ROOT\").unwrap_or(\"Can't find ROOT\")); println!(\"{}\", option_env!(\"CARGO\").unwrap_or(\"Can't find CARGO\"));\n} then we get the output: playground\nCan't find ROOT\n/playground/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/cargo So option_env! is always going to be the safer macro. env! is better if you actually want the program to crash when you can't find the environment variable.","breadcrumbs":"Taking user input » Taking user input","id":"113","title":"Taking user input"},"114":{"body":"Now that we are using Rust on the computer, we can start working with files. You will notice that now we will start to see more and more Results in our code. That is because once you start working with files and similar things, many things can go wrong. A file might not be there, or maybe the computer can't read it. You might remember that if you want to use the ? operator, it has to return a Result in the function it is in. If you can't remember the error type, you can just give it nothing and let the compiler tell you. Let's try that with a function that tries to make a number with .parse(). // ⚠️\nfn give_number(input: &str) -> Result { input.parse::()\n} fn main() { println!(\"{:?}\", give_number(\"88\")); println!(\"{:?}\", give_number(\"5\"));\n} The compiler tells us exactly what to do: error[E0308]: mismatched types --> src\\main.rs:4:5 |\n3 | fn give_number(input: &str) -> Result { | --------------- expected `std::result::Result` because of return type\n4 | input.parse::() | ^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `std::num::ParseIntError` | = note: expected enum `std::result::Result<_, ()>` found enum `std::result::Result<_, std::num::ParseIntError>` Great! So we just change the return to what the compiler says: use std::num::ParseIntError; fn give_number(input: &str) -> Result { input.parse::()\n} fn main() { println!(\"{:?}\", give_number(\"88\")); println!(\"{:?}\", give_number(\"5\"));\n} Now the program works! Ok(88)\nOk(5) So now we want to use ? to just give us the value if it works, and the error if it doesn't. But how to do this in fn main()? If we try to use ? in main, it won't work. // ⚠️\nuse std::num::ParseIntError; fn give_number(input: &str) -> Result { input.parse::()\n} fn main() { println!(\"{:?}\", give_number(\"88\")?); println!(\"{:?}\", give_number(\"5\")?);\n} It says: error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) --> src\\main.rs:8:22 |\n7 | / fn main() {\n8 | | println!(\"{:?}\", give_number(\"88\")?); | | ^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`\n9 | | println!(\"{:?}\", give_number(\"5\")?);\n10 | | } | |_- this function should return `Result` or `Option` to accept `?` But actually main() can return a Result, just like any other function. If our function works, we don't want to return anything (main() isn't giving anything to anything else). And if it doesn't work, we will return the same error. So we can write it like this: use std::num::ParseIntError; fn give_number(input: &str) -> Result { input.parse::()\n} fn main() -> Result<(), ParseIntError> { println!(\"{:?}\", give_number(\"88\")?); println!(\"{:?}\", give_number(\"5\")?); Ok(())\n} Don't forget the Ok(()) at the end: this is very common in Rust. It means Ok, inside of which is (), which is our return value. Now it prints: 88\n5 This wasn't very useful when just using .parse(), but it will be with files. That's because ? also changes error types for us. Here's what the page for the ? operator says in simple English: If you get an `Err`, it will get the inner error. Then `?` does a conversion using `From`. With that it can change specialized errors to more general ones. The error it gets is then returned. Also, Rust has a convenient Result type when using Files and similar things. It's called std::io::Result, and this is what you usually see in main() when you are using ? to open and do things to files. It's actually a type alias. It looks like this: type Result = Result; So it is a Result, but we only need to write the Result part. Now let's try working with files for the first time. std::fs is where the methods are for working with files, and with std::io::Write you can write in them. With that we can use .write_all() to write into the file. use std::fs;\nuse std::io::Write; fn main() -> std::io::Result<()> { let mut file = fs::File::create(\"myfilename.txt\")?; // Create a file with this name. // CAREFUL! If you have a file with this name already, // it will delete everything in it. file.write_all(b\"Let's put this in the file\")?; // Don't forget the b in front of \". That's because files take bytes. Ok(())\n} Then if you click on the new file myfilename.txt, it will say Let's put this in the file. We don't need to do this on two lines though, because we have the ? operator. It will pass on the result we want if it works, kind of like when you use lots of methods on an iterator. This is when ? becomes very convenient. use std::fs;\nuse std::io::Write; fn main() -> std::io::Result<()> { fs::File::create(\"myfilename.txt\")?.write_all(b\"Let's put this in the file\")?; Ok(())\n} So this is saying \"Please try to create a file and check if it worked. If it did, then use .write_all() and then check if that worked.\" And in fact, there is also a function that does both of these things together. It's called std::fs::write. Inside it you give it the file name you want, and the content you want to put inside. Again, careful! It will delete everything in that file if it already exists. Also, it lets you write a &str without b in front, because of this: pub fn write, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> AsRef<[u8]> is why you can give it either one. It's very simple: use std::fs; fn main() -> std::io::Result<()> { fs::write(\"calvin_with_dad.txt\", \"Calvin: Dad, how come old photographs are always black and white? Didn't they have color film back then?\nDad: Sure they did. In fact, those photographs *are* in color. It's just the *world* was black and white then.\nCalvin: Really?\nDad: Yep. The world didn't turn color until sometimes in the 1930s...\")?; Ok(())\n} So that's the file we will use. It's a conversation with a comic book character named Calvin and his dad, who is not serious about his question. With this we can create a file to use every time. Opening a file is just as easy as creating one. You just use open() instead of create(). After that (if it finds your file), you can do things like read_to_string(). To do that you can create a mutable String and read the file into there. It looks like this: use std::fs;\nuse std::fs::File;\nuse std::io::Read; // this is to use the function .read_to_string() fn main() -> std::io::Result<()> { fs::write(\"calvin_with_dad.txt\", \"Calvin: Dad, how come old photographs are always black and white? Didn't they have color film back then?\nDad: Sure they did. In fact, those photographs *are* in color. It's just the *world* was black and white then.\nCalvin: Really?\nDad: Yep. The world didn't turn color until sometimes in the 1930s...\")?; let mut calvin_file = File::open(\"calvin_with_dad.txt\")?; // Open the file we just made let mut calvin_string = String::new(); // This String will hold it calvin_file.read_to_string(&mut calvin_string)?; // Read the file into it calvin_string.split_whitespace().for_each(|word| print!(\"{} \", word.to_uppercase())); // Do things with the String now Ok(())\n} That will print: CALVIN: DAD, HOW COME OLD PHOTOGRAPHS ARE ALWAYS BLACK AND WHITE? DIDN'T THEY HAVE COLOR FILM BACK THEN? DAD: SURE THEY DID. IN FACT, THOSE PHOTOGRAPHS *ARE* IN COLOR. IT'S JUST THE *WORLD* WAS BLACK AND WHITE THEN. CALVIN: REALLY? DAD: YEP. THE WORLD DIDN'T TURN COLOR UNTIL SOMETIMES IN THE 1930S... Okay, what if we want to create a file but not do it if there is already another file with the same name? Maybe you don't want to delete the other file if it's already there just to make a new one. To do this, there is a struct called OpenOptions. Actually, we've been using OpenOptions all this time and didn't know it. Take a look at the source for File::open: pub fn open>(path: P) -> io::Result { OpenOptions::new().read(true).open(path.as_ref()) } Interesting, that looks like the builder pattern that we learned. It's the same for File::create: pub fn create>(path: P) -> io::Result { OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref()) } If you go to the page for OpenOptions , you can see all the methods that you can choose from. Most take a bool: append(): This means \"add to the content that's already there instead of deleting\". create(): This lets OpenOptions create a file. create_new(): This means it will only create a file if it's not there already. read(): Set this to true if you want it to be able to read a file. truncate(): Set this to true if you want to cut the file content to 0 (delete the contents) when you open it. write(): This lets it write to a file. Then at the end you use .open() with the file name, and that will give you a Result. Let's look at one example: // ⚠️\nuse std::fs;\nuse std::fs::OpenOptions; fn main() -> std::io::Result<()> { fs::write(\"calvin_with_dad.txt\", \"Calvin: Dad, how come old photographs are always black and white? Didn't they have color film back then?\nDad: Sure they did. In fact, those photographs *are* in color. It's just the *world* was black and white then.\nCalvin: Really?\nDad: Yep. The world didn't turn color until sometimes in the 1930s...\")?; let calvin_file = OpenOptions::new().write(true).create_new(true).open(\"calvin_with_dad.txt\")?; Ok(())\n} First we made an OpenOptions with new (always start with new). Then we gave it the ability to write. After that we set create_new() to true, and tried to open the file we made. It won't work, which is what we want: Error: Os { code: 80, kind: AlreadyExists, message: \"The file exists.\" } Let's try using .append() so we can write to a file. To write to the file we can use .write_all(), which is a method that tries to write in everything you give it. Also, we will use the write! macro to do the same thing. You will remember this macro from when we did impl Display for our structs. This time we are using it on a file though instead of a buffer. use std::fs;\nuse std::fs::OpenOptions;\nuse std::io::Write; fn main() -> std::io::Result<()> { fs::write(\"calvin_with_dad.txt\", \"Calvin: Dad, how come old photographs are always black and white? Didn't they have color film back then?\nDad: Sure they did. In fact, those photographs *are* in color. It's just the *world* was black and white then.\nCalvin: Really?\nDad: Yep. The world didn't turn color until sometimes in the 1930s...\")?; let mut calvin_file = OpenOptions::new() .append(true) // Now we can write without deleting it .read(true) .open(\"calvin_with_dad.txt\")?; calvin_file.write_all(b\"And it was a pretty grainy color for a while too.\\n\")?; write!(&mut calvin_file, \"That's really weird.\\n\")?; write!(&mut calvin_file, \"Well, truth is stranger than fiction.\")?; println!(\"{}\", fs::read_to_string(\"calvin_with_dad.txt\")?); Ok(())\n} This prints: Calvin: Dad, how come old photographs are always black and white? Didn't they have color film back then?\nDad: Sure they did. In fact, those photographs *are* in color. It's just the *world* was black and white then.\nCalvin: Really?\nDad: Yep. The world didn't turn color until sometimes in the 1930s...And it was a pretty grainy color for a while too.\nThat's really weird.\nWell, truth is stranger than fiction.","breadcrumbs":"Using files » Using files","id":"114","title":"Using files"},"115":{"body":"You might have noticed that Rust documentation always looks almost the same. On the left side you can see structs and traits, code examples are on the right, etc. This is because you can automatically make documentation just by typing cargo doc. Even making a project with nothing can help you learn about traits in Rust. For example, here are two structs that do almost nothing, and a fn main() that also does nothing. struct DoesNothing {}\nstruct PrintThing {} impl PrintThing { fn prints_something() { println!(\"I am printing something\"); }\n} fn main() {} But if you type cargo doc --open, you can see a lot more information than you expected. First it shows you this: Crate rust_book Structs\nDoesNothing\nPrintThing Functions\nmain But if you click on one of the structs, it will show you a lot of traits that you didn't think were there: Struct rust_book::DoesNothing\n[+] Show declaration\nAuto Trait Implementations\nimpl RefUnwindSafe for DoesNothing\nimpl Send for DoesNothing\nimpl Sync for DoesNothing\nimpl Unpin for DoesNothing\nimpl UnwindSafe for DoesNothing\nBlanket Implementations\nimpl Any for T\nwhere T: 'static + ?Sized,\n[src]\n[+]\nimpl Borrow for T\nwhere T: ?Sized,\n[src]\n[+]\nimpl BorrowMut for T\nwhere T: ?Sized,\n[src]\n[+]\nimpl From for T\n[src]\n[+]\nimpl Into for T\nwhere U: From,\n[src]\n[+]\nimpl TryFrom for T\nwhere U: Into,\n[src]\n[+]\nimpl TryInto for T\nwhere U: TryFrom, This is because of all the traits that Rust automatically makes for every type. Then if we add some documentation comments you can see them when you type cargo doc. /// This is a struct that does nothing\nstruct DoesNothing {}\n/// This struct only has one method.\nstruct PrintThing {}\n/// It just prints the same message.\nimpl PrintThing { fn prints_something() { println!(\"I am printing something\"); }\n} fn main() {} Now it will print: Crate rust_book\nStructs\nDoesNothing This is a struct that does nothing\nPrintThing This struct only has one method.\nFunctions\nmain cargo doc is very nice when you use a lot of other people's crates. Because these crates are all on different websites, it can take some time to search them all. But if you use cargo doc, you will have them all in the same place on your hard drive.","breadcrumbs":"cargo doc » cargo doc","id":"115","title":"cargo doc"},"116":{"body":"This is the end of Rust in Easy English. But I am still here, and you can let me know if you have any questions. Feel free to contact me on Twitter or add a pull request, issue, etc. You can also tell me if some parts weren't easy to understand. Rust in Easy English needs to be very easy to understand, so please let me know where the English is too difficult. Of course, Rust itself can be difficult to understand, but we can at least make sure that the English is easy.","breadcrumbs":"The end? » The end?","id":"116","title":"The end?"},"12":{"body":"See this chapter on YouTube: Video 1 , Video 2 When you start a new Rust program, it always has this code: fn main() { println!(\"Hello, world!\");\n} fn means function, main is the function that starts the program, () means that we didn't give the function any variables to start. {} is called a code block . This is the space where code lives. println! is a macro that prints to the console. A macro is like a function that writes code for you. Macros have a ! after them. We will learn about making macros later. For now, remember that ! means that it is a macro. To learn about the ;, we will create another function. First, in main we will print a number 8: fn main() { println!(\"Hello, world number {}!\", 8);\n} The {} in println! means \"put the variable inside here\". This prints Hello, world number 8!. We can put more in, just like we did before: fn main() { println!(\"Hello, worlds number {} and {}!\", 8, 9);\n} This prints Hello, worlds number 8 and 9!. Now let's create the function. fn number() -> i32 { 8\n} fn main() { println!(\"Hello, world number {}!\", number());\n} This also prints Hello, world number 8!. When Rust looks at number() it sees a function. This function: Does not take anything (because it has ()) Returns an i32. The -> (called a \"skinny arrow\") shows what the function returns. Inside the function is just 8. Because there is no ;, this is the value it returns. If it had a ;, it would not return anything (it would return a ()). Rust will not compile this if it has a ;, because the return is i32 and ; returns (), not i32: fn main() { println!(\"Hello, world number {}\", number());\n} fn number() -> i32 { 8; // ⚠️\n} 5 | fn number() -> i32 { | ------ ^^^ expected `i32`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression\n6 | 8; | - help: consider removing this semicolon This means \"you told me that number() returns an i32, but you added a ; so it doesn't return anything\". So the compiler suggests removing the semicolon. You can also write return 8; but in Rust it is normal to just remove the ; to return. When you want to give variables to a function, put them inside the (). You have to give them a name and write the type. fn multiply(number_one: i32, number_two: i32) { // Two i32s will enter the function. We will call them number_one and number_two. let result = number_one * number_two; println!(\"{} times {} is {}\", number_one, number_two, result);\n} fn main() { multiply(8, 9); // We can give the numbers directly let some_number = 10; // Or we can declare two variables let some_other_number = 2; multiply(some_number, some_other_number); // and put them in the function\n} We can also return an i32. Just take out the semicolon at the end: fn multiply(number_one: i32, number_two: i32) -> i32 { let result = number_one * number_two; println!(\"{} times {} is {}\", number_one, number_two, result); result // this is the i32 that we return\n} fn main() { let multiply_result = multiply(8, 9); // We used multiply() to print and to give the result to multiply_result\n}","breadcrumbs":"Printing 'hello, world!' » Printing 'hello, world!'","id":"12","title":"Printing 'hello, world!'"},"13":{"body":"Use let to declare a variable (declare a variable = tell Rust to make a variable). fn main() { let my_number = 8; println!(\"Hello, number {}\", my_number);\n} Variables start and end inside a code block {}. In this example, my_number ends before we call println!, because it is inside its own code block. 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\n} You can use a code block to return a value: fn main() { let my_number = { let second_number = 8; second_number + 9 // No semicolon, so the code block returns 8 + 9. // It works just like a function }; println!(\"My number is: {}\", my_number);\n} If you add a semicolon inside the block, it will return () (nothing): fn main() { let my_number = { let second_number = 8; // declare second_number, second_number + 9; // add 9 to second_number // but we didn't return it! // second_number dies now }; println!(\"My number is: {:?}\", my_number); // my_number is ()\n} So why did we write {:?} and not {}? We will talk about that now.","breadcrumbs":"Printing 'hello, world!' » Declaring variables and code blocks","id":"13","title":"Declaring variables and code blocks"},"14":{"body":"See this chapter on YouTube Simple variables in Rust can be printed with {} inside println!. But some variables can't, and you need to debug print . Debug print is printing for the programmer, because it usually shows more information. Debug sometimes doesn't look pretty, because it has extra information to help you. How do you know if you need {:?} and not {}? The compiler will tell you. For example: fn main() { let doesnt_print = (); println!(\"This will not print: {}\", doesnt_print); // ⚠️\n} When we run this, the compiler says: error[E0277]: `()` doesn't implement `std::fmt::Display` --> src\\main.rs:3:41 |\n3 | println!(\"This will not print: {}\", doesnt_print); | ^^^^^^^^^^^^ `()` cannot be formatted with the default formatter | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: required by `std::fmt::Display::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) This is a lot of information. But the important part is: you may be able to use {:?} (or {:#?} for pretty-print) instead. This means that you can try {:?}, and also {:#?} {:#?} is called \"pretty printing\". It is like {:?} but prints with different formatting over more lines. So Display means printing with {}, and Debug means printing with {:?}. One more thing: you can also use print! without ln if you don't want a new line. fn main() { print!(\"This will not print a new line\"); println!(\" so this will be on the same line\");\n} This prints This will not print a new line so this will be on the same line.","breadcrumbs":"Display and debug » Display and debug","id":"14","title":"Display and debug"},"15":{"body":"If you want to see the smallest and biggest numbers, you can use MIN and MAX. std means \"standard library\" and has all the main functions etc. for Rust. We will learn about the standard library later. But in the meantime, you can remember that this is how you get the smallest and largest number for a type. fn main() { println!(\"The smallest i8 is {} and the biggest i8 is {}.\", std::i8::MIN, std::i8::MAX); // hint: printing std::i8::MIN means \"print MIN inside of the i8 section in the standard library\" println!(\"The smallest u8 is {} and the biggest u8 is {}.\", std::u8::MIN, std::u8::MAX); println!(\"The smallest i16 is {} and the biggest i16 is {}.\", std::i16::MIN, std::i16::MAX); println!(\"The smallest u16 is {} and the biggest u16 is {}.\", std::u16::MIN, std::u16::MAX); println!(\"The smallest i32 is {} and the biggest i32 is {}.\", std::i32::MIN, std::i32::MAX); println!(\"The smallest u32 is {} and the biggest u32 is {}.\", std::u32::MIN, std::u32::MAX); println!(\"The smallest i64 is {} and the biggest i64 is {}.\", std::i64::MIN, std::i64::MAX); println!(\"The smallest u64 is {} and the biggest u64 is {}.\", std::u64::MIN, std::u64::MAX); println!(\"The smallest i128 is {} and the biggest i128 is {}.\", std::i128::MIN, std::i128::MAX); println!(\"The smallest u128 is {} and the biggest u128 is {}.\", std::u128::MIN, std::u128::MAX); } This will print: The smallest i8 is -128 and the biggest i8 is 127.\nThe smallest u8 is 0 and the biggest u8 is 255.\nThe smallest i16 is -32768 and the biggest i16 is 32767.\nThe smallest u16 is 0 and the biggest u16 is 65535.\nThe smallest i32 is -2147483648 and the biggest i32 is 2147483647.\nThe smallest u32 is 0 and the biggest u32 is 4294967295.\nThe smallest i64 is -9223372036854775808 and the biggest i64 is 9223372036854775807.\nThe smallest u64 is 0 and the biggest u64 is 18446744073709551615.\nThe smallest i128 is -170141183460469231731687303715884105728 and the biggest i128 is 170141183460469231731687303715884105727.\nThe smallest u128 is 0 and the biggest u128 is 340282366920938463463374607431768211455.","breadcrumbs":"Display and debug » Smallest and largest numbers","id":"15","title":"Smallest and largest numbers"},"16":{"body":"See this chapter on YouTube When you declare a variable with let, it is immutable (cannot be changed). This will not work: fn main() { let my_number = 8; my_number = 10; // ⚠️\n} The compiler says: error[E0384]: cannot assign twice to immutable variable my_number. This is because variables are immutable if you only write let. But sometimes you want to change your variable. To make a variable that you can change, add mut after let: fn main() { let mut my_number = 8; my_number = 10;\n} Now there is no problem. However, you cannot change the type: even mut doesn't let you do that. This will not work: fn main() { let mut my_variable = 8; // it is now an i32. That can't be changed my_variable = \"Hello, world!\"; // ⚠️\n} You will see the same \"expected\" message from the compiler: expected integer, found &str. &str is a string type that we will learn soon.","breadcrumbs":"Mutability (changing) » Mutability (changing)","id":"16","title":"Mutability (changing)"},"17":{"body":"See this chapter on YouTube Shadowing means using let to declare a new variable with the same name as another variable. It looks like mutability, but it is completely different. Shadowing looks like this: fn main() { let my_number = 8; // This is an i32 println!(\"{}\", my_number); // prints 8 let my_number = 9.2; // This is an f64 with the same name. But it's not the first my_number - it is completely different! println!(\"{}\", my_number) // Prints 9.2\n} Here we say that we \"shadowed\" my_number with a new \"let binding\". So is the first my_number destroyed? No, but when we call my_number we now get my_number the f64. And because they are in the same scope block (the same {}), we can't see the first my_number anymore. But if they are in different blocks, we can see both. For example: fn main() { let my_number = 8; // This is an i32 println!(\"{}\", my_number); // prints 8 { let my_number = 9.2; // This is an f64. It is not my_number - it is completely different! println!(\"{}\", my_number) // Prints 9.2 // But the shadowed my_number only lives until here. // The first my_number is still alive! } println!(\"{}\", my_number); // prints 8\n} So when you shadow a variable, you don't destroy it. You block it. So what is the advantage of shadowing? Shadowing is good when you need to change a variable a lot. Imagine that you want to do a lot of simple math with a variable: fn times_two(number: i32) -> i32 { number * 2\n} fn main() { let final_number = { let y = 10; let x = 9; // x starts at 9 let x = times_two(x); // shadow with new x: 18 let x = x + y; // shadow with new x: 28 x // return x: final_number is now the value of x }; println!(\"The number is now: {}\", final_number)\n} Without shadowing you would have to think of different names, even though you don't care about x: fn times_two(number: i32) -> i32 { number * 2\n} fn main() { // Pretending we are using Rust without shadowing let final_number = { let y = 10; let x = 9; // x starts at 9 let x_twice = times_two(x); // second name for x let x_twice_and_y = x_twice + y; // third name for x! x_twice_and_y // too bad we didn't have shadowing - we could have just used x }; println!(\"The number is now: {}\", final_number)\n} In general, you see shadowing in Rust in this case. It happens where you want to quickly take variable, do something to it, and do something else again. And you usually use it for quick variables that you don't care too much about.","breadcrumbs":"Mutability (changing) » Shadowing","id":"17","title":"Shadowing"},"18":{"body":"The stack, the heap, and pointers are very important in Rust. The stack and the heap are two places to keep memory in computers. The important differences are: The stack is very fast, but the heap is not so fast. It's not super slow either, but the stack is always faster. But you can't just use the stack all the time, because: Rust needs to know the size of a variable at compile time. So simple variables like i32 go on the stack, because we know their exact size. You always know that an i32 is going to be 4 bytes, because 32 bits = 4 bytes. So i32 can always go on the stack. But some types don't know the size at compile time. But the stack needs to know the exact size. So what do you do? First you put the data in the heap, because the heap can have any size of data. And then to find it a pointer goes on the stack. This is fine because we always know the size of a pointer. So then the computer first goes to the stack, reads the pointer, and follows it to the heap where the data is. Pointers sound complicated, but they are easy. Pointers are like a table of contents in a book. Imagine this book: MY BOOK TABLE OF CONTENTS Chapter Page\nChapter 1: My life 1\nChapter 2: My cat 15\nChapter 3: My job 23\nChapter 4: My family 30\nChapter 5: Future plans 43 So this is like five pointers. You can read them and find the information they are talking about. Where is the chapter \"My life\"? It's on page 1 (it points to page 1). Where is the chapter \"My job?\" It's on page 23. The pointer you usually see in Rust is called a reference . This is the important part to know: a reference points to the memory of another value. A reference means you borrow the value, but you don't own it. It's the same as our book: the table of contents doesn't own the information. It's the chapters that own the information. In Rust, references have a & in front of them. So: let my_variable = 8 makes a regular variable, but let my_reference = &my_variable makes a reference. You read my_reference = &my_variable like this: \"my_reference is a reference to my_variable\". Or: \"my_reference refers to my_variable\". This means that my_reference is only looking at the data of my_variable. my_variable still owns its data. You can also have a reference to a reference, or any number of references. fn main() { let my_number = 15; // This is an i32 let single_reference = &my_number; // This is a &i32 let double_reference = &single_reference; // This is a &&i32 let five_references = &&&&&my_number; // This is a &&&&&i32\n} These are all different types, just in the same way that \"a friend of a friend\" is different from \"a friend\".","breadcrumbs":"The stack, the heap, and pointers » The stack, the heap, and pointers","id":"18","title":"The stack, the heap, and pointers"},"19":{"body":"In Rust you can print things in almost any way you want. Here are some more things to know about printing. Adding \\n will make a new line, and \\t will make a tab: fn main() { // Note: this is print!, not println! print!(\"\\t Start with a tab\\nand move to a new line\");\n} This prints: Start with a tab\nand move to a new line Inside \"\" you can write over many lines with no problem, but be careful with the spacing: fn main() { // Note: After the first line you have to start on the far left. // If you write directly under println!, it will add the spaces println!(\"Inside quotes\nyou can write over\nmany lines\nand it will print just fine.\"); println!(\"If you forget to write on the left side, the spaces will be added when you print.\");\n} This prints: Inside quotes\nyou can write over\nmany lines\nand it will print just fine.\nIf you forget to write on the left side, the spaces will be added when you print. If you want to print characters like \\n (called \"escape characters\"), you can add an extra \\: fn main() { println!(\"Here are two escape characters: \\\\n and \\\\t\");\n} This prints: Here are two escape characters: \\n and \\t Sometimes you have too many \" and escape characters, and want Rust to ignore everything. To do this, you can add r# to the beginning and # to the end. fn main() { println!(\"He said, \\\"You can find the file at c:\\\\files\\\\my_documents\\\\file.txt.\\\" Then I found the file.\"); // We used \\ five times here println!(r#\"He said, \"You can find the file at c:\\files\\my_documents\\file.txt.\" Then I found the file.\"#)\n} This prints the same thing, but using r# makes it easier for humans to read. He said, \"You can find the file at c:\\files\\my_documents\\file.txt.\" Then I found the file.\nHe said, \"You can find the file at c:\\files\\my_documents\\file.txt.\" Then I found the file. If you need to print with a # inside, then you can start with r## and end with ##. And if you need more than one, you can add one more # on each side. Here are four examples: fn main() { let my_string = \"'Ice to see you,' he said.\"; // single quotes let quote_string = r#\"\"Ice to see you,\" he said.\"#; // double quotes let hashtag_string = r##\"The hashtag #IceToSeeYou had become very popular.\"##; // Has one # so we need at least ## let many_hashtags = r####\"\"You don't have to type ### to use a hashtag. You can just use #.\"\"####; // Has three ### so we need at least #### println!(\"{}\\n{}\\n{}\\n{}\\n\", my_string, quote_string, hashtag_string, many_hashtags); } This will print: 'Ice to see you,' he said.\n\"Ice to see you,\" he said.\nThe hashtag #IceToSeeYou had become very popular.\n\"You don't have to type ### to use a hashtag. You can just use #.\" r# has another use: with it you can use a keyword (words like let, fn, etc.) as a variable name. fn main() { let r#let = 6; // The variable's name is let let mut r#mut = 10; // This variable's name is mut\n} r# has this function because older versions of Rust had fewer keywords than Rust now. So with r# you can avoid mistakes with variable names that were not keywords before. Or maybe for some reason you really need a function to have a name like return. Then you can write this: fn r#return() -> u8 { println!(\"Here is your number.\"); 8\n} fn main() { let my_number = r#return(); println!(\"{}\", my_number);\n} This prints: Here is your number.\n8 So you probably won't need it, but if you really need to use a keyword for a variable then you can use r#. If you want to print the bytes of a &str or a char, you can just write b before the string. This works for all ASCII characters. These are all the ASCII characters: ☺☻♥♦♣♠♫☼►◄↕‼¶§▬↨↑↓→∟↔▲▼123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ So when you print this: fn main() { println!(\"{:?}\", b\"This will look like numbers\");\n} Here is the result: [84, 104, 105, 115, 32, 119, 105, 108, 108, 32, 108, 111, 111, 107, 32, 108, 105, 107, 101, 32, 110, 117, 109, 98, 101, 114, 115] For a char this is called a byte , and for a &str it's called a byte string . You can also put b and r together if you need to: fn main() { println!(\"{:?}\", br##\"I like to write \"#\".\"##);\n} That will print [73, 32, 108, 105, 107, 101, 32, 116, 111, 32, 119, 114, 105, 116, 101, 32, 34, 35, 34, 46]. There is also a Unicode escape that lets you print any Unicode character inside a string: \\u{}. A hexadecimal number goes inside the {} to print it. Here is a short example of how to get the Unicode number, and how to print it again. fn main() { println!(\"{:X}\", '행' as u32); // Cast char as u32 to get the hexadecimal value println!(\"{:X}\", 'H' as u32); println!(\"{:X}\", '居' as u32); println!(\"{:X}\", 'い' as u32); println!(\"\\u{D589}, \\u{48}, \\u{5C45}, \\u{3044}\"); // Try printing them with unicode escape \\u\n} We know that println! can print with {} (for Display) and {:?} (for Debug), plus {:#?} for pretty printing. But there are many other ways to print. For example, if you have a reference, you can use {:p} to print the pointer address . Pointer address means the location in your computer's memory. fn main() { let number = 9; let number_ref = &number; println!(\"{:p}\", number_ref);\n} This prints 0xe2bc0ffcfc or some other address. It might be different every time, depending on where your computer stores it. Or you can print binary, hexadecimal and octal: fn main() { let number = 555; println!(\"Binary: {:b}, hexadecimal: {:x}, octal: {:o}\", number, number, number);\n} This prints Binary: 1000101011, hexadecimal: 22b, octal: 1053. Or you can add numbers to change the order. The first variable will be in index 0, the next in index 1, and so on. fn main() { let father_name = \"Vlad\"; let son_name = \"Adrian Fahrenheit\"; let family_name = \"Țepeș\"; println!(\"This is {1} {2}, son of {0} {2}.\", father_name, son_name, family_name);\n} father_name is in position 0, son_name is in position 1, and family_name is in position 2. So it prints This is Adrian Fahrenheit Țepeș, son of Vlad Țepeș. Maybe you have a very complex string to print with too many variables inside the {} curly brackets. Or maybe you need to print a variable more than one time. Then it can help to add names to the {}: fn main() { println!( \"{city1} is in {country} and {city2} is also in {country},\nbut {city3} is not in {country}.\", city1 = \"Seoul\", city2 = \"Busan\", city3 = \"Tokyo\", country = \"Korea\" );\n} That will print: Seoul is in Korea and Busan is also in Korea,\nbut Tokyo is not in Korea. Very complex printing is also possible in Rust if you want to use it. Here is how to do it: {variable:padding alignment minimum.maximum} To understand this, look at the Do you want a variable name? Write that first, like when we wrote {country} above. (Then add a : after it if you want to do more things) Do you want a padding character? For example, 55 with three \"padding zeros\" looks like 00055. What alignment (left / middle / right) for the padding? Do you want a minimum length? (just write a number) Do you want a maximum length? (write a number with a . in front) For example, if I want to write \"a\" with five ㅎ characters on the left and five ㅎ characters on the right: fn main() { let letter = \"a\"; println!(\"{:ㅎ^11}\", letter);\n} This prints ㅎㅎㅎㅎㅎaㅎㅎㅎㅎㅎ. Let's look at 1) to 5) for this to understand how the compiler reads it. Do you want a variable name? {:ㅎ^11} There is no variable name. There is nothing before :. Do you want a padding character? {:ㅎ^11} Yes. ㅎ comes after the : and has a ^. < means padding with the character on the left, > means on the right, and ^ means in the middle. Do you want a minimum length? {:ㅎ^11} Yes: there is an 11 after. Do you want a maximum length? {:ㅎ^11} No: there is no number with a . before. Here is an example of many types of formatting. fn main() { let title = \"TODAY'S NEWS\"; println!(\"{:-^30}\", title); // no variable name, pad with -, put in centre, 30 characters long let bar = \"|\"; println!(\"{: <15}{: >15}\", bar, bar); // no variable name, pad with space, 15 characters each, one to the left, one to the right let a = \"SEOUL\"; let b = \"TOKYO\"; println!(\"{city1:-<15}{city2:->15}\", city1 = a, city2 = b); // variable names city1 and city2, pad with -, one to the left, one to the right\n} It prints: ---------TODAY'S NEWS---------\n| |\nSEOUL--------------------TOKYO","breadcrumbs":"More about printing » More about printing","id":"19","title":"More about printing"},"2":{"body":"I am a Canadian who lives in Korea, and I wrote Easy Rust while thinking of how to make it easy for companies here to start using it. I hope that other countries that don't use English as a first language can use it too.","breadcrumbs":"Who am I? » Who am I?","id":"2","title":"Who am I?"},"20":{"body":"See this chapter on YouTube Rust has two main types of strings: String and &str. What is the difference? &str is a simple string. When you write let my_variable = \"Hello, world!\", you create a &str. A &str is very fast. String is a more complicated string. It is a bit slower, but it has more functions. A String is a pointer, with data on the heap. Also note that &str has the & in front of it because you need a reference to use a str. That's because of the reason we saw above: the stack needs to know the size. So we give it a & that it knows the size of, and then it is happy. Also, because you use a & to interact with a str, you don't own it. But a String is an owned type. We will soon learn why that is important to know. Both &str and String are UTF-8. For example, you can write: fn main() { let name = \"서태지\"; // This is a Korean name. No problem, because a &str is UTF-8. let other_name = String::from(\"Adrian Fahrenheit Țepeș\"); // Ț and ș are no problem in UTF-8.\n} You can see in String::from(\"Adrian Fahrenheit Țepeș\") that it is easy to make a String from a &str. The two types are very closely linked together, even though they are different. You can even write emojis, thanks to UTF-8. fn main() { let name = \"😂\"; println!(\"My name is actually {}\", name);\n} On your computer that will print My name is actually 😂 unless your command line can't print it. Then it will show My name is actually �. But Rust has no problem with emojis or any other Unicode. Let's look at the reason for using a & for strs again to make sure we understand. str is a dynamically sized type (dynamically sized = the size can be different). For example, the names \"서태지\" and \"Adrian Fahrenheit Țepeș\" are not the same size: fn main() { println!(\"A String is always {:?} bytes. It is Sized.\", std::mem::size_of::()); // std::mem::size_of::() gives you the size in bytes of a type println!(\"And an i8 is always {:?} bytes. It is Sized.\", std::mem::size_of::()); println!(\"And an f64 is always {:?} bytes. It is Sized.\", std::mem::size_of::()); 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ș\"));\n} This prints: A String is always 24 bytes. It is Sized.\nAnd an i8 is always 1 bytes. It is Sized.\nAnd an f64 is always 8 bytes. It is Sized.\nBut a &str? It can be anything. '서태지' is 9 bytes. It is not Sized.\nAnd 'Adrian Fahrenheit Țepeș' is 25 bytes. It is not Sized. That is why we need a &, because & makes a pointer, and Rust knows the size of the pointer. So the pointer goes on the stack. If we wrote str, Rust wouldn't know what to do because it doesn't know the size. There are many ways to make a String. Here are some: String::from(\"This is the string text\"); This a method for String that takes text and creates a String. \"This is the string text\".to_string(). This is a method for &str that makes it a String. The format! macro. This is like println! except it creates a String instead of printing. So you can do this: fn main() { let my_name = \"Billybrobby\"; let my_country = \"USA\"; let my_home = \"Korea\"; let together = format!( \"I am {} and I come from {} but I live in {}.\", my_name, my_country, my_home );\n} Now we have a String named together , but did not print it yet. One other way to make a String is called .into() but it is a bit different because .into() isn't just for making a String. Some types can easily convert to and from another type using From and .into(). And if you have From, then you also have .into(). From is clearer because you already know the types: you know that String::from(\"Some str\") is a String from a &str. But with .into(), sometimes the compiler doesn't know: fn main() { let my_string = \"Try to make this a String\".into(); // ⚠️\n} Rust doesn't know what type you want, because many types can be made from a &str. It says, \"I can make a &str into a lot of things. Which one do you want?\" error[E0282]: type annotations needed --> src\\main.rs:2:9 |\n2 | let my_string = \"Try to make this a String\".into(); | ^^^^^^^^^ consider giving `my_string` a type So you can do this: fn main() { let my_string: String = \"Try to make this a String\".into();\n} And now you get a String.","breadcrumbs":"Strings » Strings","id":"20","title":"Strings"},"21":{"body":"See this chapter on YouTube There are two other ways to declare values, not just with let. These are const and static. Also, Rust won't use type inference: you need to write the type for them. These are for values that don't change (const means constant). The difference is that: const is for values that don't change, the name is replaced with the value when it's used, static is similar to const, but has a fixed memory location and can act as a global variable. So they are almost the same. Rust programmers almost always use const. You write them with ALL CAPITAL LETTERS, and usually outside of main so that they can live for the whole program. Two examples are: const NUMBER_OF_MONTHS: u32 = 12; and static SEASONS: [&str; 4] = [\"Spring\", \"Summer\", \"Fall\", \"Winter\"];","breadcrumbs":"const and static » const and static","id":"21","title":"const and static"},"22":{"body":"See this chapter on YouTube References are very important in Rust. Rust uses references to make sure that all memory access is safe. We know that we use & to create a reference: fn main() { let country = String::from(\"Austria\"); let ref_one = &country; let ref_two = &country; println!(\"{}\", ref_one);\n} This prints Austria. In the code, country is a String. We then created two references to country. They have the type &String, which you say is a \"reference to a String\". We could create three references or one hundred references to country and it would be no problem. But this is a problem: fn return_str() -> &str { let country = String::from(\"Austria\"); let country_ref = &country; country_ref // ⚠️\n} fn main() { let country = return_str();\n} The function return_str() creates a String, then it creates a reference to the String. Then it tries to return the reference. But the String country only lives inside the function, and then it dies. Once a variable is gone, the computer will clean up the memory and use it for something else. So after the function is over, country_ref is referring to memory that is already gone, and that's not okay. Rust prevents us from making a mistake with memory here. This is the important part about the \"owned\" type that we talked about above. Because you own a String, you can pass it around. But a &String will die if its String dies, so you don't pass around \"ownership\" with it.","breadcrumbs":"More on references » More on references","id":"22","title":"More on references"},"23":{"body":"See this chapter on YouTube If you want to use a reference to change data, you can use a mutable reference. For a mutable reference, you write &mut instead of &. fn main() { let mut my_number = 8; // don't forget to write mut here! let num_ref = &mut my_number;\n} So what are the two types? my_number is an i32, and num_ref is &mut i32 (we say a \"mutable reference to an i32\"). So let's use it to add 10 to my_number. But you can't write num_ref += 10, because num_ref is not the i32 value, it is a &i32. The value is actually inside the i32. To reach the place where the value is, we use *. * means \"I don't want the reference, I want the value behind the reference\". In other words, one * is the opposite of &. Also, one * erases one &. fn main() { let mut my_number = 8; let num_ref = &mut my_number; *num_ref += 10; // Use * to change the i32 value. println!(\"{}\", my_number); let second_number = 800; let triple_reference = &&&second_number; println!(\"Second_number = triple_reference? {}\", second_number == ***triple_reference);\n} This prints: 18\nSecond_number = triple_reference? true Because using & is called \"referencing\", using * is called \" de referencing\". Rust has two rules for mutable and immutable references. They are very important, but also easy to remember because they make sense. Rule 1 : If you have only immutable references, you can have as many as you want. 1 is fine, 3 is fine, 1000 is fine. No problem. Rule 2 : If you have a mutable reference, you can only have one. Also, you can't have an immutable reference and a mutable reference together. This is because mutable references can change the data. You could get problems if you change the data when other references are reading it. A good way to understand is to think of a Powerpoint presentation. 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. The manager can make any changes he wants, and give the computer back later. This is fine, because nobody else is looking at the presentation. Situation two is about only immutable references . Situation two: The employee is giving the presentation to 100 people. All 100 people can now see the employee's data. They all have an \"immutable reference\" to the employee's presentation. This is fine, because they can see it but nobody can change the data. Situation three is the problem situation . Situation three: The Employee gives his manager his login information. His manager now has a \"mutable reference\". Then the employee went to give the presentation to 100 people, but the manager can still login. This is not fine, because the manager can log in and do anything. Maybe his manager will log into the computer and start typing an email to his mother! Now the 100 people have to watch the manager write an email to his mother instead of the presentation. That's not what they expected to see. Here is an example of a mutable borrow with an immutable borrow: fn main() { let mut number = 10; let number_ref = &number; let number_change = &mut number; *number_change += 10; println!(\"{}\", number_ref); // ⚠️\n} The compiler prints a helpful message to show us the problem. error[E0502]: cannot borrow `number` as mutable because it is also borrowed as immutable --> src\\main.rs:4:25 |\n3 | let number_ref = &number; | ------- immutable borrow occurs here\n4 | let number_change = &mut number; | ^^^^^^^^^^^ mutable borrow occurs here\n5 | *number_change += 10;\n6 | println!(\"{}\", number_ref); | ---------- immutable borrow later used here However, this code will work. Why? fn main() { let mut number = 10; let number_change = &mut number; // create a mutable reference *number_change += 10; // use mutable reference to add 10 let number_ref = &number; // create an immutable reference println!(\"{}\", number_ref); // print the immutable reference\n} It prints 20 with no problem. It works because the compiler is smart enough to understand our code. It knows that we used number_change to change number, but didn't use it again. So here there is no problem. We are not using immutable and mutable references together. Earlier in Rust this kind of code actually generated an error, but the compiler is smarter now. It can understand not just what we type, but how we use everything.","breadcrumbs":"Mutable references » Mutable references","id":"23","title":"Mutable references"},"24":{"body":"Remember when we said that shadowing doesn't destroy a value but blocks it? Now we can use references to see this. fn main() { let country = String::from(\"Austria\"); let country_ref = &country; let country = 8; println!(\"{}, {}\", country_ref, country);\n} Does this print Austria, 8 or 8, 8? It prints Austria, 8. First we declare a String called country. Then we create a reference country_ref to this string. Then we shadow country with 8, which is an i32. But the first country was not destroyed, so country_ref still says \"Austria\", not \"8\". Here is the same code with some comments to show how it works: fn main() { let country = String::from(\"Austria\"); // Now we have a String called country let country_ref = &country; // country_ref is a reference to this data. It's not going to change let country = 8; // Now we have a variable called country that is an i8. But it has no relation to the other one, or to country_ref println!(\"{}, {}\", country_ref, country); // country_ref still refers to the data of String::from(\"Austria\") that we gave it.\n}","breadcrumbs":"Mutable references » Shadowing again","id":"24","title":"Shadowing again"},"25":{"body":"See this chapter on YouTube: immutable references and mutable references References are very useful for functions. The rule in Rust on values is: a value can only have one owner. This code will not work: fn print_country(country_name: String) { println!(\"{}\", country_name);\n} fn main() { let country = String::from(\"Austria\"); print_country(country); // We print \"Austria\" print_country(country); // ⚠️ That was fun, let's do it again!\n} It does not work because country is destroyed. Here's how: Step 1: We create the String called country. country is the owner. Step 2: We give country to print_country. print_country doesn't have an ->, so it doesn't return anything. After print_country finishes, our String is now dead. Step 3: We try to give country to print_country, but we already did that. We don't have country to give anymore. We can make print_country give the String back, but it is a bit awkward. fn print_country(country_name: String) -> String { println!(\"{}\", country_name); country_name // return it here\n} fn main() { let country = String::from(\"Austria\"); let country = print_country(country); // we have to use let here now to get the String back print_country(country);\n} Now it prints: Austria\nAustria The much better way to fix this is by adding &. fn print_country(country_name: &String) { println!(\"{}\", country_name);\n} fn main() { let country = String::from(\"Austria\"); print_country(&country); // We print \"Austria\" print_country(&country); // That was fun, let's do it again!\n} Now print_country() is a function that takes a reference to a String: a &String. Also, we give it a reference to country by writing &country. This says \"you can look at it, but I will keep it\". Now let's do something similar with a mutable reference. Here is an example of a function that uses a mutable variable. fn add_hungary(country_name: &mut String) { // first we say that the function takes a mutable reference country_name.push_str(\"-Hungary\"); // push_str() adds a &str to a String println!(\"Now it says: {}\", country_name);\n} fn main() { let mut country = String::from(\"Austria\"); add_hungary(&mut country); // we also need to give it a mutable reference.\n} This prints Now it says: Austria-Hungary. So to conclude: fn function_name(variable: String) takes a String and owns it. If it doesn't return anything, then the variable dies inside the function. 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. fn main() { let country = String::from(\"Austria\"); // country is not mutable, but we are going to print Austria-Hungary. How? adds_hungary(country);\n} fn adds_hungary(mut country: String) { // Here's how: adds_hungary takes the String and declares it mutable! country.push_str(\"-Hungary\"); println!(\"{}\", country);\n} How is this possible? It is because mut country is not a reference: adds_hungary owns country now. (Remember, it takes String and not &String). The moment you call adds_hungary, it becomes the full owner. country has nothing to do with String::from(\"Austria\") anymore. So adds_hungary can take country as mutable, and it is perfectly safe to do so. Remember our employee Powerpoint and manager situation above? In this situation it is like the employee just giving his whole computer to the manager. The employee won't ever touch it again, so the manager can do anything he wants to it.","breadcrumbs":"Giving references to functions » Giving references to functions","id":"25","title":"Giving references to functions"},"26":{"body":"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. 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 ) 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);\n} 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!\n} 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 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: fn prints_country(country_name: String) { println!(\"{}\", country_name);\n} fn main() { let country = String::from(\"Kiribati\"); prints_country(country); prints_country(country); // ⚠️\n} But now we understand the message. error[E0382]: use of moved value: `country` --> src\\main.rs:4:20 |\n2 | let country = String::from(\"Kiribati\"); | ------- move occurs because `country` has type `std::string::String`, which does not implement the `Copy` trait\n3 | prints_country(country); | ------- value moved here\n4 | 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() 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. fn prints_country(country_name: String) { println!(\"{}\", country_name);\n} fn main() { let country = String::from(\"Kiribati\"); 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);\n} 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: 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\n} 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 }\n} It prints: It's 5 words long.\nIt's 10 words long.\n...\nIt's 250 words long. That's 50 clones. Here it is using a reference instead, which is better: fn get_length(input: &String) { println!(\"It's {} words long.\", input.split_whitespace().count());\n} 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); }\n} Instead of 50 clones, it's zero.","breadcrumbs":"Copy types » Copy types","id":"26","title":"Copy types"},"27":{"body":"A variable without a value is called an \"uninitialized\" variable. Uninitialized means \"hasn't started yet\". They are simple: just write let and the variable name: fn main() { let my_variable; // ⚠️\n} But you can't use it yet, and Rust won't compile if anything is uninitialized. But sometimes they can be useful. A good example is when: You have a code block and the value for your variable is inside it, and The variable needs to live outside of the code block. fn loop_then_return(mut counter: i32) -> i32 { loop { counter += 1; if counter % 50 == 0 { break; } } counter\n} fn main() { let my_number; { // Pretend we need to have this code block let number = { // Pretend there is code here to make a number // Lots of code, and finally: 57 }; my_number = loop_then_return(number); } println!(\"{}\", my_number);\n} This prints 100. You can see that my_number was declared in the main() function, so it lives until the end. But it gets its value from inside a loop. However, that value lives as long as my_number, because my_number has the value. And if you wrote let my_number = loop_then_return(number) inside the block, it would just die right away. It helps to imagine if you simplify the code. loop_then_return(number) gives the result 100, so let's delete it and write 100 instead. Also, now we don't need number so we will delete it too. Now it looks like this: fn main() { let my_number; { my_number = 100; } println!(\"{}\", my_number);\n} So it's almost like saying let my_number = { 100 };. Also note that my_number is not mut. We didn't give it a value until we gave it 50, so it never changed its value. In the end, the real code for my_number is just let my_number = 100;.","breadcrumbs":"Copy types » Variables without values","id":"27","title":"Variables without values"},"28":{"body":"Rust has a lot of types for making a collection. Collections are for when you need more than one value in one spot. For example, you could have information on all the cities in your country inside one variable. We will start with arrays, which are fastest but also have the least functionality. They are kind of like &str in that way.","breadcrumbs":"Collection types » Collection types","id":"28","title":"Collection types"},"29":{"body":"An array is data inside square brackets: []. Arrays: must not change their size, must only contain the same type. They are very fast, however. The type of an array is: [type; number]. For example, the type of [\"One\", \"Two\"] is [&str; 2]. This means that even these two arrays have different types: fn main() { let array1 = [\"One\", \"Two\"]; // This one is type [&str; 2] let array2 = [\"One\", \"Two\", \"Five\"]; // But this one is type [&str; 3]. Different type!\n} Here is a good tip: to know the type of a variable, you can \"ask\" the compiler by giving it bad instructions. For example: fn main() { let seasons = [\"Spring\", \"Summer\", \"Autumn\", \"Winter\"]; let seasons2 = [\"Spring\", \"Summer\", \"Fall\", \"Autumn\", \"Winter\"]; seasons.ddd(); // ⚠️ seasons2.thd(); // ⚠️ as well\n} The compiler says, \"What? There's no .ddd() method for seasons and no .thd() method for seasons 2 either!!\" as you can see: error[E0599]: no method named `ddd` found for array `[&str; 4]` in the current scope --> src\\main.rs:4:13 |\n4 | seasons.ddd(); // | ^^^ method not found in `[&str; 4]` error[E0599]: no method named `thd` found for array `[&str; 5]` in the current scope --> src\\main.rs:5:14 |\n5 | seasons2.thd(); // | ^^^ method not found in `[&str; 5]` So it tells you method not found in `[&str; 4]`, which is the type. If you want an array with all the same value, you can declare it like this: fn main() { let my_array = [\"a\"; 10]; println!(\"{:?}\", my_array);\n} This prints [\"a\", \"a\", \"a\", \"a\", \"a\", \"a\", \"a\", \"a\", \"a\", \"a\"]. This method is used a lot to create buffers. For example, let mut buffer = [0; 640] creates an array of 640 zeroes. Then we can change zero to other numbers in order to add data. You can index (get) entries in an array with []. The first entry is [0], the second is [1], and so on. fn main() { let my_numbers = [0, 10, -20]; println!(\"{}\", my_numbers[1]); // prints 10\n} You can get a slice (a piece) of an array. First you need a &, because the compiler doesn't know the size. Then you can use .. to show the range. For example, let's use this array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]. fn main() { let array_of_ten = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let three_to_five = &array_of_ten[2..5]; let start_at_two = &array_of_ten[1..]; let end_at_five = &array_of_ten[..5]; let everything = &array_of_ten[..]; println!(\"Three to five: {:?}, start at two: {:?}, end at five: {:?}, everything: {:?}\", three_to_five, start_at_two, end_at_five, everything);\n} Remember that: Index numbers start at 0 (not 1) Index ranges are exclusive (they do not include the last number) So [0..2] means the first index and the second index (0 and 1). Or you can call it the \"zeroth and first\" index. It doesn't have the third item, which is index 2. You can also have an inclusive range, which means it includes the last number too. To do this, add = to write ..= instead of ... So instead of [0..2] you can write [0..=2] if you want the first, second, and third item.","breadcrumbs":"Collection types » Arrays","id":"29","title":"Arrays"},"3":{"body":"Rust in Easy English was written from July to August 2020, and is over 400 pages long. You can contact me here or on LinkedIn or on Twitter if you have any questions. If you see anything wrong or have a pull request to make, go ahead. Over 20 people have already helped out by fixing typos and problems in the code, so you can too. I'm not the world's best Rust expert so I always like to hear new ideas or see where I can make the book better. Part 1 - Rust in your browser Rust Playground 🚧 and ⚠️ Comments Types Primitive types Type inference Floats Printing 'hello, world!' Declaring variables and code blocks Display and debug Smallest and largest numbers Mutability (changing) Shadowing The stack, the heap, and pointers More about printing Strings const and static More on references Mutable references Shadowing again Giving references to functions Copy types Variables without values Collection types Arrays Vectors Tuples Control flow Structs Enums Enums to use multiple types Loops Implementing structs and enums Destructuring References and the dot operator Generics Option and Result Option Result Other collections HashMap (and BTreeMap) HashSet and BTreeSet BinaryHeap VecDeque The ? operator When panic and unwrap are good Traits The From trait Taking a String and a &str in a function Chaining methods Iterators How an iterator works Closures |_| in a closure Helpful methods for closures and iterators The dbg! macro and .inspect Types of &str Lifetimes Interior mutability Cell RefCell Mutex RwLock Cow Type aliases Importing and renaming inside a function The todo! macro Rc Multiple threads Closures in functions impl Trait Arc Channels Reading Rust documentation assert_eq! Searching [src] button Information on traits Attributes Box Box around traits Default and the builder pattern Deref and DerefMut Crates and modules Testing Test-driven development External crates rand rayon serde regex chrono A tour of the standard library Arrays char Integers Floats Bool Vec String OsString and CString Mem Prelude Time Other-macros Writing macros Part 2 - Rust on your computer Cargo Taking_user_input Using files Cargo doc The end?","breadcrumbs":"Writing Rust in Easy English » Writing Rust in Easy English","id":"3","title":"Writing Rust in Easy English"},"30":{"body":"See this chapter on YouTube In the same way that we have &str and String, we have arrays and vectors. Arrays are faster with less functionality, and vectors are slower with more functionality. (Of course, Rust is always very fast so vectors are not slow, just slow er than arrays.) The type is written Vec, and you can also just call it a \"vec\". There are two main ways to declare a vector. One is like with String using new: 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 my_vec.push(name2);\n} You can see that a Vec always has something else inside it, and that's what the <> (angle brackets) are for. A Vec is a vector with one or more Strings. You can also have more types inside. For example: Vec<(i32, i32)> this is a Vec where each item is a tuple: (i32, i32). Vec> this is a Vec that has Vecs of Strings. Say for example you wanted to save your favourite book as a Vec. Then you do it again with another book, and get another Vec. To hold both books, you would put them into another Vec and that would be a Vec>. Instead of using .push() to make Rust decide the type, you can just declare the type. fn main() { let mut my_vec: Vec = Vec::new(); // The compiler knows the type // so there is no error.\n} You can see that items in vectors must have the same type. Another easy way to create a vector is with the vec! macro. It looks like an array declaration, but has vec! in front of it. fn main() { let mut my_vec = vec![8, 10, 10];\n} The type is Vec. You call it a \"Vec of i32s\". And a Vec is a \"Vec of strings\". And a Vec> is a \"Vec of a vec of strings\". You can slice a vector too, just like in an array. fn main() { let vec_of_ten = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // Everything is the same as above except we added vec!. let three_to_five = &vec_of_ten[2..5]; let start_at_two = &vec_of_ten[1..]; let end_at_five = &vec_of_ten[..5]; let everything = &vec_of_ten[..]; println!(\"Three to five: {:?},\nstart at two: {:?}\nend at five: {:?}\neverything: {:?}\", three_to_five, start_at_two, end_at_five, everything);\n} Because a vec is slower than an array, we can use some methods to make it faster. A vec has a capacity , which means the space given to the vector. When you push a new item on the vector, it gets closer and closer to the capacity. Then if you go past the capacity, it will make its capacity double and copy the items into the new space. This is called reallocation. We'll use a method called .capacity() to look at the capacity of a vector as we add items to it. For example: fn main() { let mut num_vec = Vec::new(); println!(\"{}\", num_vec.capacity()); // 0 elements: prints 0 num_vec.push('a'); // add one character println!(\"{}\", num_vec.capacity()); // 1 element: prints 4. Vecs with 1 item always start with capacity 4 num_vec.push('a'); // add one more num_vec.push('a'); // add one more num_vec.push('a'); // add one more println!(\"{}\", num_vec.capacity()); // 4 elements: still prints 4. num_vec.push('a'); // add one more println!(\"{}\", num_vec.capacity()); // prints 8. We have 5 elements, but it doubled 4 to 8 to make space\n} This prints: 0\n4\n4\n8 So this vector has two reallocations: 0 to 4, and 4 to 8. We can make it faster: fn main() { let mut num_vec = Vec::with_capacity(8); // Give it capacity 8 num_vec.push('a'); // add one character println!(\"{}\", num_vec.capacity()); // prints 8 num_vec.push('a'); // add one more println!(\"{}\", num_vec.capacity()); // prints 8 num_vec.push('a'); // add one more println!(\"{}\", num_vec.capacity()); // prints 8. num_vec.push('a'); // add one more num_vec.push('a'); // add one more // Now we have 5 elements println!(\"{}\", num_vec.capacity()); // Still 8\n} This vector has 0 reallocations, which is better. So if you think you know how many elements you need, you can use Vec::with_capacity() to make it faster. You remember that you can use .into() to make a &str into a String. You can also use it to make an array into a Vec. You have to tell .into() that you want a Vec, but you don't have to choose the type of Vec. If you don't want to choose, you can write Vec<_>. fn main() { let my_vec: Vec = [1, 2, 3].into(); let my_vec2: Vec<_> = [9, 0, 10].into(); // Vec<_> means \"choose the Vec type for me\" // Rust will choose Vec\n}","breadcrumbs":"Vectors » Vectors","id":"30","title":"Vectors"},"31":{"body":"See this chapter on YouTube Tuples in Rust use (). We have seen many empty tuples already, because nothing in a function actually means an empty tuple: fn do_something() {} is actually short for: fn do_something() -> () {} That function gets nothing (an empty tuple), and returns nothing (an empty tuple). So we have been using tuples a lot already. When you don't return anything in a function, you actually return an empty tuple. fn just_prints() { println!(\"I am printing\"); // Adding ; means we return an empty tuple\n} fn main() {} But tuples can hold many things, and can hold different types too. Items inside a tuple are also indexed with numbers 0, 1, 2, and so on. But to access them, you use a . instead of a []. Let's put a whole bunch of types into a single tuple. fn main() { let random_tuple = (\"Here is a name\", 8, vec!['a'], 'b', [8, 9, 10], 7.7); println!( \"Inside the tuple is: First item: {:?}\nSecond item: {:?}\nThird item: {:?}\nFourth item: {:?}\nFifth item: {:?}\nSixth item: {:?}\", random_tuple.0, random_tuple.1, random_tuple.2, random_tuple.3, random_tuple.4, random_tuple.5, )\n} This prints: Inside the tuple is: First item: \"Here is a name\"\nSecond item: 8\nThird item: ['a']\nFourth item: 'b'\nFifth item: [8, 9, 10]\nSixth item: 7.7 That tuple is of type (&str, i32, Vec, char, [i32; 3], f64). You can use a tuple to create multiple variables. Take a look at this code: fn main() { let str_vec = vec![\"one\", \"two\", \"three\"];\n} str_vec has three items in it. What if we want to pull them out? That's where we can use a tuple. fn main() { let str_vec = vec![\"one\", \"two\", \"three\"]; let (a, b, c) = (str_vec[0], str_vec[1], str_vec[2]); // call them a, b, and c println!(\"{:?}\", b);\n} That prints \"two\", which is what b is. This is called destructuring . That is because first the variables are inside a structure, but then we made a, b, and c that are not inside a structure. If you need to destructure but don't want all the variables, you can use _. fn main() { let str_vec = vec![\"one\", \"two\", \"three\"]; let (_, _, variable) = (str_vec[0], str_vec[1], str_vec[2]);\n} Now it only creates a variable called variable but doesn't make a variable for the others. There are many more collection types, and many more ways to use arrays, vecs, and tuples. We will learn more about them too, but first we will learn control flow.","breadcrumbs":"Tuples » Tuples","id":"31","title":"Tuples"},"32":{"body":"See this chapter on YouTube: Part 1 and Part 2 Control flow means telling your code what to do in different situations. The simplest control flow is if. fn main() { let my_number = 5; if my_number == 7 { println!(\"It's seven\"); }\n} Also note that you use == and not =. == is to compare, = is to assign (to give a value). Also note that we wrote if my_number == 7 and not if (my_number == 7). You don't need brackets with if in Rust. else if and else give you more control: fn main() { let my_number = 5; if my_number == 7 { println!(\"It's seven\"); } else if my_number == 6 { println!(\"It's six\") } else { println!(\"It's a different number\") }\n} This prints It's a different number because it's not equal to 7 or 6. You can add more conditions with && (and) and || (or). fn main() { let my_number = 5; if my_number % 2 == 1 && my_number > 0 { // % 2 means the number that remains after diving by two println!(\"It's a positive odd number\"); } else if my_number == 6 { println!(\"It's six\") } else { println!(\"It's a different number\") }\n} This prints It's a positive odd number because when you divide it by 2 you have a remainder of 1, and it's greater than 0. You can see that too much if, else, and else if can be difficult to read. In this case you can use match instead, which looks much cleaner. But you must match for every possible result. For example, this will not work: fn main() { let my_number: u8 = 5; match my_number { 0 => println!(\"it's zero\"), 1 => println!(\"it's one\"), 2 => println!(\"it's two\"), // ⚠️ }\n} The compiler says: error[E0004]: non-exhaustive patterns: `3u8..=std::u8::MAX` not covered --> src\\main.rs:3:11 |\n3 | match my_number { | ^^^^^^^^^ pattern `3u8..=std::u8::MAX` not covered This means \"you told me about 0 to 2, but u8s can go up to 255. What about 3? What about 4? What about 5?\" And so on. So you can add _ which means \"anything else\". fn main() { let my_number: u8 = 5; match my_number { 0 => println!(\"it's zero\"), 1 => println!(\"it's one\"), 2 => println!(\"it's two\"), _ => println!(\"It's some other number\"), }\n} That prints It's some other number. Remember this for match: You write match and then make a {} code block. Write the pattern on the left and use a => fat arrow to say what to do when it matches. Each line is called an \"arm\". Put a comma between the arms (not a semicolon). You can declare a value with a match: fn main() { let my_number = 5; let second_number = match my_number { 0 => 0, 5 => 10, _ => 2, };\n} second_number will be 10. Do you see the semicolon at the end? That is because, after the match is over, we actually told the compiler this: let second_number = 10; You can match on more complicated things too. You use a tuple to do it. fn main() { let sky = \"cloudy\"; let temperature = \"warm\"; match (sky, temperature) { (\"cloudy\", \"cold\") => println!(\"It's dark and unpleasant today\"), (\"clear\", \"warm\") => println!(\"It's a nice day\"), (\"cloudy\", \"warm\") => println!(\"It's dark but not bad\"), _ => println!(\"Not sure what the weather is.\"), }\n} This prints It's dark but not bad because it matches \"cloudy\" and \"warm\" for sky and temperature. You can even put if inside of match. This is called a \"match guard\": fn main() { let children = 5; let married = true; match (children, married) { (children, married) if married == false => println!(\"Not married with {} children\", children), (children, married) if children == 0 && married == true => println!(\"Married but no children\"), _ => println!(\"Married? {}. Number of children: {}.\", married, children), }\n} This will print Married? true. Number of children: 5. You can use _ as many times as you want in a match. In this match on colours, we have three but only check one at a time. fn match_colours(rbg: (i32, i32, i32)) { match rbg { (r, _, _) if r < 10 => println!(\"Not much red\"), (_, b, _) if b < 10 => println!(\"Not much blue\"), (_, _, g) if g < 10 => println!(\"Not much green\"), _ => println!(\"Each colour has at least 10\"), }\n} fn main() { let first = (200, 0, 0); let second = (50, 50, 50); let third = (200, 50, 0); match_colours(first); match_colours(second); match_colours(third); } This prints: Not much blue\nEach colour has at least 10\nNot much green This also shows how match statements work, because in the first example it only printed Not much blue. But first also has not much green. A match statement always stops when it finds a match, and doesn't check the rest. This is a good example of code that compiles well but is not the code you want. You can make a really big match statement to fix it, but it is probably better to use a for loop. We will talk about loops soon. A match has to return the same type. So you can't do this: fn main() { let my_number = 10; let some_variable = match my_number { 10 => 8, _ => \"Not ten\", // ⚠️ };\n} The compiler tells you that: error[E0308]: `match` arms have incompatible types --> src\\main.rs:17:14 |\n15 | let some_variable = match my_number { | _________________________-\n16 | | 10 => 8, | | - this is found to be of type `{integer}`\n17 | | _ => \"Not ten\", | | ^^^^^^^^^ expected integer, found `&str`\n18 | | }; | |_____- `match` arms have incompatible types This will also not work, for the same reason: fn main() { let some_variable = if my_number == 10 { 8 } else { \"something else \"}; // ⚠️\n} But this works, because it's not a match so you have a different let statement each time: fn main() { let my_number = 10; if my_number == 10 { let some_variable = 8; } else { let some_variable = \"Something else\"; }\n} You can also use @ to give a name to the value of a match expression, and then you can use it. In this example we match an i32 input in a function. If it's 4 or 13 we want to use that number in a println! statement. Otherwise, we don't need to use it. fn match_number(input: i32) { match input { number @ 4 => println!(\"{} is an unlucky number in China (sounds close to 死)!\", number), number @ 13 => println!(\"{} is unlucky in North America, lucky in Italy! In bocca al lupo!\", number), _ => println!(\"Looks like a normal number\"), }\n} fn main() { match_number(50); match_number(13); match_number(4);\n} This prints: Looks like a normal number\n13 is unlucky in North America, lucky in Italy! In bocca al lupo!\n4 is an unlucky number in China (sounds close to 死)!","breadcrumbs":"Control flow » Control flow","id":"32","title":"Control flow"},"33":{"body":"See this chapter on YouTube: Part 1 and Part 2 With structs, you can create your own type. You will use structs all the time in Rust because they are so convenient. Structs are created with the keyword struct. The name of a struct should be in UpperCamelCase (capital letter for each word, no spaces). If you write a struct in all lowercase, the compiler will tell you. There are three types of structs. One is a \"unit struct\". Unit means \"doesn't have anything\". For a unit struct, you just write the name and a semicolon. struct FileDirectory;\nfn main() {} The next is a tuple struct, or an unnamed struct. It is \"unnamed\" because you only need to write the types, not the field names. Tuple structs are good when you need a simple struct and don't need to remember names. struct Colour(u8, u8, u8); fn main() { let my_colour = Colour(50, 0, 50); // Make a colour out of RGB (red, green, blue) println!(\"The second part of the colour is: {}\", my_colour.1);\n} This prints The second part of the colour is: 0. The third type is the named struct. This is probably the most common struct. In this struct you declare field names and types inside a {} code block. Note that you don't write a semicolon after a named struct, because there is a whole code block after it. struct Colour(u8, u8, u8); // Declare the same Colour tuple struct struct SizeAndColour { size: u32, colour: Colour, // And we put it in our new named struct\n} fn main() { let my_colour = Colour(50, 0, 50); let size_and_colour = SizeAndColour { size: 150, colour: my_colour };\n} You separate fields by commas in a named struct too. For the last field you can add a comma or not - it's up to you. SizeAndColour had a comma after colour: struct Colour(u8, u8, u8); // Declare the same Colour tuple struct struct SizeAndColour { size: u32, colour: Colour, // And we put it in our new named struct\n} fn main() {} but you don't need it. But it can be a good idea to always put a comma, because sometimes you will change the order of the fields: struct Colour(u8, u8, u8); // Declare the same Colour tuple struct struct SizeAndColour { size: u32, colour: Colour // No comma here\n} fn main() {} Then we decide to change the order... struct SizeAndColour { colour: Colour // ⚠️ Whoops! Now this doesn't have a comma. size: u32,\n} fn main() {} But it is not very important either way so you can choose whether to use a comma or not. Let's create a Country struct to give an example. The Country struct has the fields population, capital, and leader_name. struct Country { population: u32, capital: String, leader_name: String\n} fn main() { let population = 500_000; let capital = String::from(\"Elista\"); let leader_name = String::from(\"Batu Khasikov\"); let kalmykia = Country { population: population, capital: capital, leader_name: leader_name, };\n} Did you notice that we wrote the same thing twice? We wrote population: population, capital: capital, and leader_name: leader_name. Actually, you don't need to do that. If the field name and variable name are the same, you don't have to write it twice. struct Country { population: u32, capital: String, leader_name: String\n} fn main() { let population = 500_000; let capital = String::from(\"Elista\"); let leader_name = String::from(\"Batu Khasikov\"); let kalmykia = Country { population, capital, leader_name, };\n}","breadcrumbs":"Structs » Structs","id":"33","title":"Structs"},"34":{"body":"See this chapter on YouTube: Part 1 , Part 2 , Part 3 and Part 4 An enum is short for enumerations. They look very similar to a struct, but are different. Here is the difference: Use a struct when you want one thing AND another thing. Use an enum when you want one thing OR another thing. So structs are for many things together, while enums are for many choices together. To declare an enum, write enum and use a code block with the options, separated by commas. Just like a struct, the last part can have a comma or not. We will create an enum called ThingsInTheSky: enum ThingsInTheSky { Sun, Stars,\n} fn main() {} This is an enum because you can either see the sun, or the stars: you have to choose one. These are called variants . // create the enum with two choices\nenum ThingsInTheSky { Sun, Stars,\n} // With this function we can use an i32 to create ThingsInTheSky.\nfn create_skystate(time: i32) -> ThingsInTheSky { match time { 6..=18 => ThingsInTheSky::Sun, // Between 6 and 18 hours we can see the sun _ => ThingsInTheSky::Stars, // Otherwise, we can see stars }\n} // With this function we can match against the two choices in ThingsInTheSky.\nfn check_skystate(state: &ThingsInTheSky) { match state { ThingsInTheSky::Sun => println!(\"I can see the sun!\"), ThingsInTheSky::Stars => println!(\"I can see the stars!\") }\n} fn main() { let time = 8; // it's 8 o'clock let skystate = create_skystate(time); // create_skystate returns a ThingsInTheSky check_skystate(&skystate); // Give it a reference so it can read the variable skystate\n} This prints I can see the sun!. You can add data to an enum too. enum ThingsInTheSky { Sun(String), // Now each variant has a string Stars(String),\n} fn create_skystate(time: i32) -> ThingsInTheSky { match time { 6..=18 => ThingsInTheSky::Sun(String::from(\"I can see the sun!\")), // Write the strings here _ => ThingsInTheSky::Stars(String::from(\"I can see the stars!\")), }\n} fn check_skystate(state: &ThingsInTheSky) { match state { ThingsInTheSky::Sun(description) => println!(\"{}\", description), // Give the string the name description so we can use it ThingsInTheSky::Stars(n) => println!(\"{}\", n), // Or you can name it n. Or anything else - it doesn't matter }\n} fn main() { let time = 8; // it's 8 o'clock let skystate = create_skystate(time); // create_skystate returns a ThingsInTheSky check_skystate(&skystate); // Give it a reference so it can read the variable skystate\n} This prints the same thing: I can see the sun! You can also \"import\" an enum so you don't have to type so much. Here's an example where we have to type Mood:: every time we match on our mood: enum Mood { Happy, Sleepy, NotBad, Angry,\n} fn match_mood(mood: &Mood) -> i32 { let happiness_level = match mood { Mood::Happy => 10, // Here we type Mood:: every time Mood::Sleepy => 6, Mood::NotBad => 7, Mood::Angry => 2, }; happiness_level\n} fn main() { let my_mood = Mood::NotBad; let happiness_level = match_mood(&my_mood); println!(\"Out of 1 to 10, my happiness is {}\", happiness_level);\n} It prints Out of 1 to 10, my happiness is 7. Let's import so we can type less. To import everything, write *. Note: it's the same key as * for dereferencing but is completely different. enum Mood { Happy, Sleepy, NotBad, Angry,\n} fn match_mood(mood: &Mood) -> i32 { use Mood::*; // We imported everything in Mood. Now we can just write Happy, Sleepy, etc. let happiness_level = match mood { Happy => 10, // We don't have to write Mood:: anymore Sleepy => 6, NotBad => 7, Angry => 2, }; happiness_level\n} fn main() { let my_mood = Mood::Happy; let happiness_level = match_mood(&my_mood); println!(\"Out of 1 to 10, my happiness is {}\", happiness_level);\n} Parts of an enum can also be turned into an integer. That's because Rust gives each arm of an enum a number that starts with 0 for its own use. You can do things with it if your enum doesn't have any other data in it. enum Season { Spring, // If this was Spring(String) or something it wouldn't work Summer, Autumn, Winter,\n} fn main() { use Season::*; let four_seasons = vec![Spring, Summer, Autumn, Winter]; for season in four_seasons { println!(\"{}\", season as u32); }\n} This prints: 0\n1\n2\n3 Though you can give it a different number, if you want - Rust doesn't care and can use it in the same way. Just add an = and your number to the variant that you want to have a number. You don't have to give all of them a number. But if you don't, Rust will just add 1 from the arm before to give it a number. enum Star { BrownDwarf = 10, RedDwarf = 50, YellowStar = 100, RedGiant = 1000, DeadStar, // Think about this one. What number will it have?\n} fn main() { use Star::*; let starvec = vec![BrownDwarf, RedDwarf, YellowStar, RedGiant]; for star in starvec { match star as u32 { size if size <= 80 => println!(\"Not the biggest star.\"), // Remember: size doesn't mean anything. It's just a name we chose so we can print it size if size >= 80 => println!(\"This is a good-sized star.\"), _ => println!(\"That star is pretty big!\"), } } println!(\"What about DeadStar? It's the number {}.\", DeadStar as u32);\n} This prints: Not the biggest star.\nNot the biggest star.\nThis is a good-sized star.\nThis is a good-sized star.\nWhat about DeadStar? It's the number 1001. DeadStar would have been number 4, but now it's 1001.","breadcrumbs":"Enums » Enums","id":"34","title":"Enums"},"35":{"body":"You know that items in a Vec, array, etc. all need the same type (only tuples are different). But you can actually use an enum to put different types in. Imagine we want to have a Vec with u32s or i32s. Of course, you can make a Vec<(u32, i32)> (a vec with (u32, i32) tuples) but we only want one each time. So here you can use an enum. Here is a simple example: enum Number { U32(u32), I32(i32),\n} fn main() {} So there are two variants: the U32 variant with a u32 inside, and the I32 variant with i32 inside. U32 and I32 are just names we made. They could have been UThirtyTwo or IThirtyTwo or anything else. Now, if we put them into a Vec we just have a Vec, and the compiler is happy because it's all the same type. The compiler doesn't care that we have either u32 or i32 because they are all inside a single type called Number. And because it's an enum, you have to pick one, which is what we want. We will use the .is_positive() method to pick. If it's true then we will choose U32, and if it's false then we will choose I32. Now the code looks like this: enum Number { U32(u32), I32(i32),\n} fn get_number(input: i32) -> Number { let number = match input.is_positive() { true => Number::U32(input as u32), // change it to u32 if it's positive false => Number::I32(input), // otherwise just give the number because it's already i32 }; number\n} fn main() { let my_vec = vec![get_number(-800), get_number(8)]; for item in my_vec { match item { Number::U32(number) => println!(\"It's a u32 with the value {}\", number), Number::I32(number) => println!(\"It's an i32 with the value {}\", number), } }\n} This prints what we wanted to see: It's an i32 with the value -800\nIt's a u32 with the value 8","breadcrumbs":"Enums » Enums to use multiple types","id":"35","title":"Enums to use multiple types"},"36":{"body":"With loops you can tell Rust to continue something until you want it to stop. You use loop to start a loop that does not stop, unless you tell it when to break. fn main() { // This program will never stop loop { }\n} So let's tell the compiler when it can break. fn main() { let mut counter = 0; // set a counter to 0 loop { counter +=1; // increase the counter by 1 println!(\"The counter is now: {}\", counter); if counter == 5 { // stop when counter == 5 break; } }\n} This will print: The counter is now: 1\nThe counter is now: 2\nThe counter is now: 3\nThe counter is now: 4\nThe counter is now: 5 If you have a loop inside of a loop, you can give them names. With names, you can tell Rust which loop to break out of. Use ' (called a \"tick\") and a : to give it a name: fn main() { let mut counter = 0; let mut counter2 = 0; println!(\"Now entering the first loop.\"); 'first_loop: loop { // Give the first loop a name counter += 1; println!(\"The counter is now: {}\", counter); if counter > 9 { // Starts a second loop inside this loop println!(\"Now entering the second loop.\"); 'second_loop: loop { // now we are inside 'second_loop println!(\"The second counter is now: {}\", counter2); counter2 += 1; if counter2 == 3 { break 'first_loop; // Break out of 'first_loop so we can exit the program } } } }\n} This will print: Now entering the first loop.\nThe counter is now: 1\nThe counter is now: 2\nThe counter is now: 3\nThe counter is now: 4\nThe counter is now: 5\nThe counter is now: 6\nThe counter is now: 7\nThe counter is now: 8\nThe counter is now: 9\nThe counter is now: 10\nNow entering the second loop.\nThe second counter is now: 0\nThe second counter is now: 1\nThe second counter is now: 2 A while loop is a loop that continues while something is still true. Each loop, Rust will check if it is still true. If it becomes false, Rust will stop the loop. fn main() { let mut counter = 0; while counter < 5 { counter +=1; println!(\"The counter is now: {}\", counter); }\n} A for loop lets you tell Rust what to do each time. But in a for loop, the loop stops after a certain number of times. for loops use ranges very often. You use .. and ..= to create a range. .. creates an exclusive range: 0..3 creates 0, 1, 2. ..= creates an inclusive range: 0..=3 = 0, 1, 2, 3. fn main() { for number in 0..3 { println!(\"The number is: {}\", number); } for number in 0..=3 { println!(\"The next number is: {}\", number); }\n} This prints: The number is: 0\nThe number is: 1\nThe number is: 2\nThe next number is: 0\nThe next number is: 1\nThe next number is: 2\nThe next number is: 3 Also notice that number becomes the variable name for 0..3. We could have called it n, or ntod_het___hno_f, or anything. We can then use that name in println!. If you don't need a variable name, use _. fn main() { for _ in 0..3 { println!(\"Printing the same thing three times\"); }\n} This prints: Printing the same thing three times\nPrinting the same thing three times\nPrinting the same thing three times because we didn't give it any number to print each time. And actually, if you give a variable name and don't use it, Rust will tell you: fn main() { for number in 0..3 { println!(\"Printing the same thing three times\"); }\n} This prints the same thing as above. The program compiles fine, but Rust will remind you that you didn't use number: warning: unused variable: `number` --> src\\main.rs:2:9 |\n2 | for number in 0..3 { | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_number` Rust suggests writing _number instead of _. Putting _ in front of a variable name means \"maybe I will use it later\". But using just _ means \"I don't care about this variable at all\". So you can put _ in front of variable names if you will use them later and don't want the compiler to tell you about them. You can also use break to return a value. You write the value right after break and use a ;. Here is an example with a loop and a break that gives my_number its value. fn main() { let mut counter = 5; let my_number = loop { counter +=1; if counter % 53 == 3 { break counter; } }; println!(\"{}\", my_number);\n} This prints 56. break counter; means \"break and return the value of counter\". And because the whole block starts with let, my_number gets the value. Now that we know how to use loops, here is a better solution to our match problem with colours from before. It is a better solution because we want to compare everything, and a for loop looks at every item. fn match_colours(rbg: (i32, i32, i32)) { println!(\"Comparing a colour with {} red, {} blue, and {} green:\", rbg.0, rbg.1, rbg.2); let new_vec = vec![(rbg.0, \"red\"), (rbg.1, \"blue\"), (rbg.2, \"green\")]; // Put the colours in a vec. Inside are tuples with the colour names let mut all_have_at_least_10 = true; // Start with true. We will set it to false if one colour is less than 10 for item in new_vec { if item.0 < 10 { all_have_at_least_10 = false; // Now it's false println!(\"Not much {}.\", item.1) // And we print the colour name. } } if all_have_at_least_10 { // Check if it's still true, and print if true println!(\"Each colour has at least 10.\") } println!(); // Add one more line\n} fn main() { let first = (200, 0, 0); let second = (50, 50, 50); let third = (200, 50, 0); match_colours(first); match_colours(second); match_colours(third);\n} This prints: Comparing a colour with 200 red, 0 blue, and 0 green:\nNot much blue.\nNot much green. Comparing a colour with 50 red, 50 blue, and 50 green:\nEach colour has at least 10. Comparing a colour with 200 red, 50 blue, and 0 green:\nNot much green.","breadcrumbs":"Loops » Loops","id":"36","title":"Loops"},"37":{"body":"This is where you can start to give your structs and enums some real power. To call functions on a struct or an enum, use an impl block. These functions are called methods . There are two kinds of methods in an impl block. Methods: these take self (or &self or &mut self ). Regular methods use a . (a period). .clone() is an example of a regular method. Associated functions (known as \"static\" methods in some languages): these do not take self. Associated means \"related to\". They are written differently, using ::. String::from() is an associated function, and so is Vec::new(). You see associated functions most often used to create new variables. In our example we are going to create animals and print them. For a new struct or enum, you need to give it Debug if you want to use {:?} to print, so we will do that. If you write #[derive(Debug)] above the struct or enum then you can print it with {:?}. These messages with #[] are called attributes . You can sometimes use them to tell the compiler to give your struct an ability like Debug. There are many attributes and we will learn about them later. But derive is probably the most common and you see it a lot above structs and enums. #[derive(Debug)]\nstruct Animal { age: u8, animal_type: AnimalType,\n} #[derive(Debug)]\nenum AnimalType { Cat, Dog,\n} impl Animal { fn new() -> Self { // Self means Animal. //You can also write Animal instead of Self Self { // When we write Animal::new(), we always get a cat that is 10 years old age: 10, animal_type: AnimalType::Cat, } } fn change_to_dog(&mut self) { // because we are inside Animal, &mut self means &mut Animal // use .change_to_dog() to change the cat to a dog // with &mut self we can change it println!(\"Changing animal to dog!\"); self.animal_type = AnimalType::Dog; } fn change_to_cat(&mut self) { // use .change_to_cat() to change the dog to a cat // with &mut self we can change it println!(\"Changing animal to cat!\"); self.animal_type = AnimalType::Cat; } fn check_type(&self) { // we want to read self match self.animal_type { AnimalType::Dog => println!(\"The animal is a dog\"), AnimalType::Cat => println!(\"The animal is a cat\"), } }\n} fn main() { let mut new_animal = Animal::new(); // Associated function to create a new animal // It is a cat, 10 years old new_animal.check_type(); new_animal.change_to_dog(); new_animal.check_type(); new_animal.change_to_cat(); new_animal.check_type();\n} This prints: The animal is a cat\nChanging animal to dog!\nThe animal is a dog\nChanging animal to cat!\nThe animal is a cat Remember that Self (the type Self) and self (the variable self) are abbreviations. (abbreviation = short way to write) So in our code, Self = Animal. Also, fn change_to_dog(&mut self) means fn change_to_dog(&mut Animal). Here is one more small example. This time we will use impl on an enum: enum Mood { Good, Bad, Sleepy,\n} impl Mood { fn check(&self) { match self { Mood::Good => println!(\"Feeling good!\"), Mood::Bad => println!(\"Eh, not feeling so good\"), Mood::Sleepy => println!(\"Need sleep NOW\"), } }\n} fn main() { let my_mood = Mood::Sleepy; my_mood.check();\n} This prints Need sleep NOW.","breadcrumbs":"Implementing structs and enums » Implementing structs and enums","id":"37","title":"Implementing structs and enums"},"38":{"body":"Let's look at some more destructuring. You can get the values from a struct or enum by using let backwards. We learned that this is destructuring, because you get variables that are not part of a structure. Now you have the values separately. First a simple example: struct Person { // make a simple struct for a person name: String, real_name: String, height: u8, happiness: bool\n} fn main() { let papa_doc = Person { // create variable papa_doc name: \"Papa Doc\".to_string(), real_name: \"Clarence\".to_string(), height: 170, happiness: false }; let Person { // destructure papa_doc name: a, real_name: b, height: c, happiness: d } = papa_doc; println!(\"They call him {} but his real name is {}. He is {} cm tall and is he happy? {}\", a, b, c, d);\n} This prints: They call him Papa Doc but his real name is Clarence. He is 170 cm tall and is he happy? false You can see that it's backwards. First we say let papa_doc = Person { fields } to create the struct. Then we say let Person { fields } = papa_doc to destructure it. You don't have to write name: a - you can just write name. But here we write name: a because we want to use a variable with the name a. Now a bigger example. In this example we have a City struct. We give it a new function to make it. Then we have a process_city_values function to do things with the values. In the function we just create a Vec, but you can imagine that we can do much more after we destructure it. struct City { name: String, name_before: String, population: u32, date_founded: u32,\n} impl City { fn new(name: String, name_before: String, population: u32, date_founded: u32) -> Self { Self { name, name_before, population, date_founded, } }\n} fn process_city_values(city: &City) { let City { name, name_before, population, date_founded, } = city; // now we have the values to use separately let two_names = vec![name, name_before]; println!(\"The city's two names are {:?}\", two_names);\n} fn main() { let tallinn = City::new(\"Tallinn\".to_string(), \"Reval\".to_string(), 426_538, 1219); process_city_values(&tallinn);\n} This prints The city's two names are [\"Tallinn\", \"Reval\"].","breadcrumbs":"Destructuring » Destructuring","id":"38","title":"Destructuring"},"39":{"body":"We learned that when you have a reference, you need to use * to get to the value. A reference is a different type, so this won't work: fn main() { let my_number = 9; let reference = &my_number; println!(\"{}\", my_number == reference); // ⚠️\n} The compiler prints: error[E0277]: can't compare `{integer}` with `&{integer}` --> src\\main.rs:5:30 |\n5 | println!(\"{}\", my_number == reference); | ^^ no implementation for `{integer} == &{integer}` So we change line 5 to println!(\"{}\", my_number == *reference); and now it prints true because it's now i32 == i32, not i32 == &i32. This is called dereferencing. But when you use a method, Rust will dereference for you. The . in a method is called the dot operator, and it does dereferencing for free. First, let's make a struct with one u8 field. Then we will make a reference to it and try to compare. It will not work: struct Item { number: u8,\n} fn main() { let item = Item { number: 8, }; let reference_number = &item.number; // reference number type is &u8 println!(\"{}\", reference_number == 8); // ⚠️ &u8 and u8 cannot be compared\n} To make it work, we need to dereference: println!(\"{}\", *reference_number == 8);. But with the dot operator, we don't need *. For example: struct Item { number: u8,\n} fn main() { let item = Item { number: 8, }; let reference_item = &item; println!(\"{}\", reference_item.number == 8); // we don't need to write *reference_item.number\n} Now let's create a method for Item that compares number to another number. We don't need to use * anywhere: struct Item { number: u8,\n} impl Item { fn compare_number(&self, other_number: u8) { // takes a reference to self println!(\"Are {} and {} equal? {}\", self.number, other_number, self.number == other_number); // We don't need to write *self.number }\n} fn main() { let item = Item { number: 8, }; let reference_item = &item; // This is type &Item let reference_item_two = &reference_item; // This is type &&Item item.compare_number(8); // the method works reference_item.compare_number(8); // it works here too reference_item_two.compare_number(8); // and here } So just remember: when you use the . operator, you don't need to worry about *.","breadcrumbs":"References and the dot operator » References and the dot operator","id":"39","title":"References and the dot operator"},"4":{"body":"This book has two parts. In Part 1, you will learn as much Rust as you can just in your browser. You can actually learn almost everything you need to know without installing Rust, so Part 1 is very long. Then at the end is Part 2. It is much shorter, and is about Rust on your computer. That's where you will learn everything else you need to know that you can only do outside of a browser. Some examples are: working with files, taking user input, graphics, and personal settings. Hopefully, by the end of Part 1 you will like Rust enough that you will install it. And if you don't, no problem - Part 1 teaches you so much that you won't mind.","breadcrumbs":"Writing Rust in Easy English » Part 1 - Rust in your browser","id":"4","title":"Part 1 - Rust in your browser"},"40":{"body":"In functions, you write what type to take as input: fn return_number(number: i32) -> i32 { println!(\"Here is your number.\"); number\n} fn main() { let number = return_number(5);\n} But what if you want to take more than just i32? You can use generics for this. Generics means \"maybe one type, maybe another type\". For generics, you use angle brackets with the type inside, like this: This means \"any type you put into the function\". Usually, generics uses types with one capital letter (T, U, V, etc.), though you don't have to just use one letter. This is how you change the function to make it generic: fn return_number(number: T) -> T { println!(\"Here is your number.\"); number\n} fn main() { let number = return_number(5);\n} The important part is the after the function name. Without this, Rust will think that T is a concrete (concrete = not generic) type, like String or i8. This is easier to understand if we write out a type name. See what happens when we change T to MyType: fn return_number(number: MyType) -> MyType { // ⚠️ println!(\"Here is your number.\"); number\n} As you can see, MyType is concrete, not generic. So we need to write this and so now it works: fn return_number(number: MyType) -> MyType { println!(\"Here is your number.\"); number\n} fn main() { let number = return_number(5);\n} So the single letter T is for human eyes, but the part after the function name is for the compiler's \"eyes\". Without it, it's not generic. Now we will go back to type T, because Rust code usually uses T. You will remember that some types in Rust are Copy , some are Clone , some are Display , some are Debug , and so on. With Debug , we can print with {:?}. So now you can see that we have a problem if we want to print T: fn print_number(number: T) { println!(\"Here is your number: {:?}\", number); // ⚠️\n} fn main() { print_number(5);\n} print_number needs Debug to print number, but is T a type with Debug? Maybe not. Maybe it doesn't have #[derive(Debug)], who knows. The compiler doesn't know either, so it gives an error: error[E0277]: `T` doesn't implement `std::fmt::Debug` --> src\\main.rs:29:43 |\n29 | println!(\"Here is your number: {:?}\", number); | ^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` T doesn't implement Debug . So do we implement Debug for T? No, because we don't know what T is. But we can tell the function: \"Don't worry, because any type T for this function will have Debug\". use std::fmt::Debug; // Debug is located at std::fmt::Debug. So now we can just write 'Debug'. fn print_number(number: T) { // is the important part println!(\"Here is your number: {:?}\", number);\n} fn main() { print_number(5);\n} So now the compiler knows: \"Okay, this type T is going to have Debug\". Now the code works, because i32 has Debug. Now we can give it many types: String, &str, and so on, because they all have Debug. Now we can create a struct and give it Debug with #[derive(Debug)], so now we can print it too. Our function can take i32, the struct Animal, and more: use std::fmt::Debug; #[derive(Debug)]\nstruct Animal { name: String, age: u8,\n} fn print_item(item: T) { println!(\"Here is your item: {:?}\", item);\n} fn main() { let charlie = Animal { name: \"Charlie\".to_string(), age: 1, }; let number = 55; print_item(charlie); print_item(number);\n} This prints: Here is your item: Animal { name: \"Charlie\", age: 1 }\nHere 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. Next is type U, and the two variables num_1 and num_2 have type U (U is some sort of number). We want to compare them, so we need PartialOrd. That trait lets us use things like <, >, ==, and so on. We want to print them too, so we require Display for U as well. use std::fmt::Display;\nuse std::cmp::PartialOrd; fn compare_and_display(statement: T, num_1: U, num_2: U) { println!(\"{}! Is {} greater than {}? {}\", statement, num_1, num_2, num_1 > num_2);\n} fn main() { compare_and_display(\"Listen up!\", 9, 8);\n} This prints Listen up!! Is 9 greater than 8? true. So fn compare_and_display(statement: T, num_1: U, num_2: U) says: The function name is compare_and_display, The first type is T, and it is generic. It must be a type that can print with {}. The next type is U, and it is generic. It must be a type that can print with {}. Also, it must be a type that can compare (use >, <, and ==). Now we can give compare_and_display different types. statement can be a String, a &str, anything with Display. To make generic functions easier to read, we can also write it like this with where right before the code block: use std::cmp::PartialOrd;\nuse std::fmt::Display; fn compare_and_display(statement: T, num_1: U, num_2: U)\nwhere T: Display, U: Display + PartialOrd,\n{ println!(\"{}! Is {} greater than {}? {}\", statement, num_1, num_2, num_1 > num_2);\n} fn main() { compare_and_display(\"Listen up!\", 9, 8);\n} Using where is a good idea when you have many generic types. Also note: If you have one type T and another type T, they must be the same. If you have one type T and another type U, they can be different. But they can also be the same. For example: use std::fmt::Display; fn say_two(statement_1: T, statement_2: U) { // Type T needs Display, type U needs Display println!(\"I have two things to say: {} and {}\", statement_1, statement_2);\n} fn main() { say_two(\"Hello there!\", String::from(\"I hate sand.\")); // Type T is a &str, but type U is a String. say_two(String::from(\"Where is Padme?\"), String::from(\"Is she all right?\")); // Both types are String.\n} This prints: I have two things to say: Hello there! and I hate sand.\nI have two things to say: Where is Padme? and Is she all right?","breadcrumbs":"Generics » Generics","id":"40","title":"Generics"},"41":{"body":"We understand enums and generics now, so we can understand Option and Result. Rust uses these two enums to make code safer. We will start with Option.","breadcrumbs":"Option and Result » Option and Result","id":"41","title":"Option and Result"},"42":{"body":"You use Option when you have a value that might exist, or might not exist. When a value exists it is Some(value) and when it doesn't it's just None, Here is an example of bad code that can be improved with Option. // ⚠️\nfn take_fifth(value: Vec) -> i32 { value[4]\n} fn main() { let new_vec = vec![1, 2]; let index = take_fifth(new_vec);\n} When we run the code, it panics. Here is the message: thread 'main' panicked at 'index out of bounds: the len is 2 but the index is 4', src\\main.rs:34:5 Panic means that the program stops before the problem happens. Rust sees that the function wants something impossible, and stops. It \"unwinds the stack\" (takes the values off the stack) and tells you \"sorry, I can't do that\". So now we will change the return type from i32 to Option. This means \"give me a Some(i32) if it's there, and give me None if it's not\". We say that the i32 is \"wrapped\" in an Option, which means that it's inside an Option. You have to do something to get the value out. fn take_fifth(value: Vec) -> Option { if value.len() < 5 { // .len() gives the length of the vec. // It must be at least 5. None } else { Some(value[4]) }\n} fn main() { let new_vec = vec![1, 2]; let bigger_vec = vec![1, 2, 3, 4, 5]; println!(\"{:?}, {:?}\", take_fifth(new_vec), take_fifth(bigger_vec));\n} This prints None, Some(5). This is good, because now we don't panic anymore. But how do we get the value 5? We can get the value inside an option with .unwrap(), but be careful with .unwrap(). It's just like unwrapping a present: maybe there's something good inside, or maybe there's an angry snake inside. You only want to .unwrap() if you are sure. If you unwrap a value that is None, the program will panic. // ⚠️\nfn take_fifth(value: Vec) -> Option { if value.len() < 5 { None } else { Some(value[4]) }\n} fn main() { let new_vec = vec![1, 2]; let bigger_vec = vec![1, 2, 3, 4, 5]; println!(\"{:?}, {:?}\", take_fifth(new_vec).unwrap(), // this one is None. .unwrap() will panic! take_fifth(bigger_vec).unwrap() );\n} The message is: thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src\\main.rs:14:9 But we don't have to use .unwrap(). We can use a match. Then we can print the value we have Some, and not touch it if we have None. For example: fn take_fifth(value: Vec) -> Option { if value.len() < 5 { None } else { Some(value[4]) }\n} fn handle_option(my_option: Vec