1 00:00:02,080 --> 00:00:03,910 My name is Nathan Stocks. 2 00:00:03,910 --> 00:00:07,060 I work at GitHub for my day job, but my opinions 3 00:00:07,060 --> 00:00:10,810 on Rust are my own and do not represent any official GitHub 4 00:00:10,810 --> 00:00:11,680 stance. 5 00:00:11,680 --> 00:00:15,760 So I'm also an independent game developer and an online course 6 00:00:15,760 --> 00:00:17,500 instructor with O'Reilly teaching 7 00:00:17,500 --> 00:00:22,060 Rust, which is a fantastic systems language that I love. 8 00:00:22,060 --> 00:00:24,410 If you have questions during this presentation, 9 00:00:24,410 --> 00:00:26,050 please save them till the end. 10 00:00:26,050 --> 00:00:28,120 We have lunch right after this session, 11 00:00:28,120 --> 00:00:30,700 and I'm happy to stay here the entire lunch 12 00:00:30,700 --> 00:00:32,770 and answer all sorts of questions, OK. 13 00:00:32,770 --> 00:00:34,720 I bet you're interested in Rust because you 14 00:00:34,720 --> 00:00:36,300 came to Intro to Rust. 15 00:00:36,300 --> 00:00:38,050 I'm glad you showed up because we're going 16 00:00:38,050 --> 00:00:39,730 to have a fantastic time today. 17 00:00:39,730 --> 00:00:43,600 This is a whirlwind tour of some of the most important things 18 00:00:43,600 --> 00:00:46,420 that I teach in depth in my longer courses. 19 00:00:46,420 --> 00:00:48,280 If you find this interesting, I encourage 20 00:00:48,280 --> 00:00:51,640 you to make something with Rust because that 21 00:00:51,640 --> 00:00:53,380 is how you will really learn. 22 00:00:53,380 --> 00:00:57,310 So without further ado, Rust is awesome. 23 00:00:57,310 --> 00:00:58,780 What is Rust? 24 00:00:58,780 --> 00:01:00,550 It's a systems programming language 25 00:01:00,550 --> 00:01:03,910 pursuing the trifecta, safety, which 26 00:01:03,910 --> 00:01:07,990 is guaranteed at compile time, concurrency, 27 00:01:07,990 --> 00:01:11,020 which is a lot easier when things are safe, 28 00:01:11,020 --> 00:01:15,370 and blazingly fast speed due to zero cost abstractions 29 00:01:15,370 --> 00:01:17,320 and other nice things. 30 00:01:17,320 --> 00:01:20,740 High level scripting languages like Ruby or Python 31 00:01:20,740 --> 00:01:24,610 will get you safety but not concurrency or speed. 32 00:01:24,610 --> 00:01:28,060 On the other hand, systems languages like C or C++ will 33 00:01:28,060 --> 00:01:31,150 give you speed and some access to concurrency, 34 00:01:31,150 --> 00:01:33,410 but forget about safety. 35 00:01:33,410 --> 00:01:36,040 So where did Rust come from? 36 00:01:36,040 --> 00:01:40,300 Rust was started in 2006 as a personal project of a Mozilla 37 00:01:40,300 --> 00:01:42,310 employee named Graydom Hoare. 38 00:01:42,310 --> 00:01:46,210 Mozilla started sponsoring Rust officially in 2009, 39 00:01:46,210 --> 00:01:50,320 and version 1.0 was released in 2015, 40 00:01:50,320 --> 00:01:52,420 which makes Rust about four years 41 00:01:52,420 --> 00:01:55,810 old after a nine-year incubation period. 42 00:01:55,810 --> 00:02:01,690 Now, why would Mozilla sponsor a systems programming language? 43 00:02:01,690 --> 00:02:04,570 Well, because they were sick of C++ and wanted a better 44 00:02:04,570 --> 00:02:07,150 language to program Firefox in. 45 00:02:07,150 --> 00:02:10,390 Did you hear about Firefox Quantum in 2017? 46 00:02:10,390 --> 00:02:12,010 It was a big update. 47 00:02:12,010 --> 00:02:16,480 Suddenly, Firefox was over twice as fast and less buggy. 48 00:02:16,480 --> 00:02:17,620 Why? 49 00:02:17,620 --> 00:02:20,710 Because the core of Firefox was rewritten in Rust. 50 00:02:20,710 --> 00:02:25,390 Today, there's about 1.5 million lines of Rust in Firefox. 51 00:02:25,390 --> 00:02:27,430 So that's where Rust came from. 52 00:02:27,430 --> 00:02:31,150 Let's talk about some of the reasons why Rust is awesome. 53 00:02:31,150 --> 00:02:33,940 I mentioned Rust is blazingly fast. 54 00:02:33,940 --> 00:02:36,400 It's also very memory efficient because it 55 00:02:36,400 --> 00:02:40,930 has no garbage collector and a very minimal runtime. 56 00:02:40,930 --> 00:02:43,390 You can scale it up to use dozens 57 00:02:43,390 --> 00:02:46,240 of cores and a powerful server, or scale it down 58 00:02:46,240 --> 00:02:50,080 to run on a tiny microcontroller with a few kilobytes of RAM. 59 00:02:50,080 --> 00:02:52,060 But that's not all. 60 00:02:52,060 --> 00:02:54,670 Rust is safe and reliable. 61 00:02:54,670 --> 00:03:00,520 Rust guarantees, guarantees memory safety and thread safety 62 00:03:00,520 --> 00:03:02,480 at compile time. 63 00:03:02,480 --> 00:03:06,310 There are whole classes of bugs that Rust eliminates, 64 00:03:06,310 --> 00:03:08,470 dangling pointers, use-after-free, 65 00:03:08,470 --> 00:03:12,070 double-free, null pointer references, buffer overflow, 66 00:03:12,070 --> 00:03:14,210 data races. 67 00:03:14,210 --> 00:03:17,210 Rust has great, high-quality documentation 68 00:03:17,210 --> 00:03:19,880 in the form of both books you can read 69 00:03:19,880 --> 00:03:22,100 and online documentation. 70 00:03:22,100 --> 00:03:24,230 There's a built-in way to document 71 00:03:24,230 --> 00:03:27,830 your own code via comments written in Markdown syntax. 72 00:03:27,830 --> 00:03:31,130 And Rust has a built-in way to convert those comments 73 00:03:31,130 --> 00:03:33,080 into a searchable website. 74 00:03:33,080 --> 00:03:38,030 As a result, every Rust project can have high quality 75 00:03:38,030 --> 00:03:40,940 documentation, including yours. 76 00:03:40,940 --> 00:03:44,900 The standard library in Rust is documented this way. 77 00:03:44,900 --> 00:03:48,320 Rust has a built-in way to write and run tests for your code, 78 00:03:48,320 --> 00:03:51,870 including running tests on code embedded in your documentation, 79 00:03:51,870 --> 00:03:55,190 so your documentation actually stays relevant. 80 00:03:55,190 --> 00:03:58,860 Rust currently has tier one support for eight platforms, 81 00:03:58,860 --> 00:04:02,300 including Mac, Linux, and Windows, as you would expect. 82 00:04:02,300 --> 00:04:04,760 It also has tier two or three support 83 00:04:04,760 --> 00:04:07,880 for over 80 additional platforms, including 84 00:04:07,880 --> 00:04:12,170 exotic things like WebAssembly, microcontrollers, iOS 85 00:04:12,170 --> 00:04:17,900 and Android, NVIDIA GPUs, BSDs, Redox, the Rust operating 86 00:04:17,900 --> 00:04:23,690 system, or Linux on ARM, MIPS, PowerPC, or SPARC. 87 00:04:23,690 --> 00:04:26,180 The Rust community is fantastic and is 88 00:04:26,180 --> 00:04:30,380 known for being friendly, safe, and welcoming 89 00:04:30,380 --> 00:04:33,830 with a code of conduct that embraces diversity. 90 00:04:33,830 --> 00:04:36,740 The community does a lot of planning and looking ahead 91 00:04:36,740 --> 00:04:37,970 to things in the future. 92 00:04:37,970 --> 00:04:40,400 The whole process takes place on GitHub, which 93 00:04:40,400 --> 00:04:42,200 makes it very transparent. 94 00:04:42,200 --> 00:04:45,440 One of the interesting planning topics is around additions. 95 00:04:45,440 --> 00:04:49,400 Last year, the 2018 edition of Rust was released. 96 00:04:49,400 --> 00:04:51,650 The addition concept is to release 97 00:04:51,650 --> 00:04:54,380 a big set of syntactically breaking changes 98 00:04:54,380 --> 00:04:58,820 as an opt-in set of features every three years while still 99 00:04:58,820 --> 00:05:03,440 supporting the older additions and the binary compatibility 100 00:05:03,440 --> 00:05:07,110 between the additions, forever. 101 00:05:07,110 --> 00:05:10,880 So in between editions, there's a dot release steadily every 102 00:05:10,880 --> 00:05:14,300 six weeks that focuses on performance improvements 103 00:05:14,300 --> 00:05:18,350 and other non-breaking fixes or enhancements. 104 00:05:18,350 --> 00:05:22,340 The Rust compiler emits useful error messages. 105 00:05:22,340 --> 00:05:25,130 That's really important because even though the Rust 106 00:05:25,130 --> 00:05:29,820 compiler is very friendly, it's always very, very strict. 107 00:05:29,820 --> 00:05:34,140 I encourage you to look at the compiler as your friend, 108 00:05:34,140 --> 00:05:36,110 as your friend who cares about you. 109 00:05:36,110 --> 00:05:40,700 Because dealing with an error at your desk in the day 110 00:05:40,700 --> 00:05:45,770 is so much nicer than dealing with a segfault in production 111 00:05:45,770 --> 00:05:48,980 in the middle of night. 112 00:05:48,980 --> 00:05:51,680 Editor support for Rust is getting really good. 113 00:05:51,680 --> 00:05:54,890 Auto completion, type inspections, auto formatting, 114 00:05:54,890 --> 00:05:58,190 syntax highlighting, and more is available for most 115 00:05:58,190 --> 00:06:01,190 major editors and IDEs. 116 00:06:01,190 --> 00:06:04,640 Rust comes with a fantastic tool called Cargo. 117 00:06:04,640 --> 00:06:06,530 Cargo is a package manager. 118 00:06:06,530 --> 00:06:07,760 Wait. 119 00:06:07,760 --> 00:06:13,190 A package manager for a viable systems programming language? 120 00:06:13,190 --> 00:06:14,060 Yes. 121 00:06:14,060 --> 00:06:19,120 Finally, systems programmers can have nice things too. 122 00:06:19,120 --> 00:06:22,430 You use Cargo to search for, install, and manage packages 123 00:06:22,430 --> 00:06:23,450 that you want to use. 124 00:06:23,450 --> 00:06:25,760 Cargo is also the build system. 125 00:06:25,760 --> 00:06:27,440 No more make files. 126 00:06:27,440 --> 00:06:31,730 Cargo is also the test runner and the documentation 127 00:06:31,730 --> 00:06:33,350 generator and-- 128 00:06:33,350 --> 00:06:35,420 sorry, my slides are not updating. 129 00:06:35,420 --> 00:06:37,550 There we go-- et cetera. 130 00:06:37,550 --> 00:06:42,140 It's like all the good things of NPM, and Pip, and Bundler, 131 00:06:42,140 --> 00:06:44,700 and Make all rolled together. 132 00:06:44,700 --> 00:06:46,110 Let's make a project. 133 00:06:46,110 --> 00:06:49,490 So if you run Cargo new hello and hit Enter, 134 00:06:49,490 --> 00:06:51,710 Cargo will happily and colorfully 135 00:06:51,710 --> 00:06:54,390 create a project named hello for you. 136 00:06:54,390 --> 00:06:57,080 So let's take a look at what Cargo created for us. 137 00:06:57,080 --> 00:06:59,270 A hello directory with a config file 138 00:06:59,270 --> 00:07:03,080 named Cargo.toml and a source subdirectory 139 00:07:03,080 --> 00:07:04,910 with a main.rs file. 140 00:07:04,910 --> 00:07:07,430 So config files in Rust use the TOML format, 141 00:07:07,430 --> 00:07:11,960 which stands for Tom's Obvious Minimal Language. 142 00:07:11,960 --> 00:07:14,690 Rust source code files use the dot rs extensions, 143 00:07:14,690 --> 00:07:16,580 as you can see on main.rs here. 144 00:07:16,580 --> 00:07:19,010 Let's open up Cargo.toml and take a look. 145 00:07:19,010 --> 00:07:21,920 Cargo.toml is the config file for your project, 146 00:07:21,920 --> 00:07:22,860 all in one place. 147 00:07:22,860 --> 00:07:25,850 In fact, it is the authoritative source of information 148 00:07:25,850 --> 00:07:27,140 about your project. 149 00:07:27,140 --> 00:07:29,430 Name is the name of your project, 150 00:07:29,430 --> 00:07:31,820 not the name of the directory or your repo. 151 00:07:31,820 --> 00:07:34,880 Rust uses semantic versioning, meaning the three version 152 00:07:34,880 --> 00:07:36,650 numbers all have a meaning. 153 00:07:36,650 --> 00:07:39,800 Cargo can usually, magically, figure out your name and email 154 00:07:39,800 --> 00:07:42,560 address, and it will set you up with the latest 155 00:07:42,560 --> 00:07:45,890 edition by default, but you can change that. 156 00:07:45,890 --> 00:07:50,450 Now let's open up main.rs in the source directory. 157 00:07:50,450 --> 00:07:52,820 It already has a Hello, world program for us. 158 00:07:52,820 --> 00:07:55,250 Oh, what a fantastic tool Cargo is. 159 00:07:55,250 --> 00:07:56,300 What a helpful language. 160 00:07:56,300 --> 00:07:57,680 Let's go back to our terminal. 161 00:07:57,680 --> 00:08:02,870 So Cargo run will both build and run your executable. 162 00:08:02,870 --> 00:08:04,970 Now, let's pause for a second and go over 163 00:08:04,970 --> 00:08:06,350 the roadmap for this talk. 164 00:08:06,350 --> 00:08:08,490 I already introduced myself. 165 00:08:08,490 --> 00:08:10,740 I told you some awesome things about Rust, 166 00:08:10,740 --> 00:08:12,950 and then I showed you how to create, compile, and run 167 00:08:12,950 --> 00:08:14,360 a Rust project. 168 00:08:14,360 --> 00:08:17,780 So now I'm going to unleash a firehose of Rust language 169 00:08:17,780 --> 00:08:18,350 information. 170 00:08:18,350 --> 00:08:20,150 This is the "crash" in the crash course. 171 00:08:20,150 --> 00:08:24,050 And then I'm going to top it off with why Rust's ownership 172 00:08:24,050 --> 00:08:25,950 model is a game changer. 173 00:08:25,950 --> 00:08:27,800 So let's start with variables. 174 00:08:27,800 --> 00:08:29,510 They're pretty important. 175 00:08:29,510 --> 00:08:32,120 Rust uses curly braces and semicolons 176 00:08:32,120 --> 00:08:35,390 and intentionally mimics as much syntax from other languages 177 00:08:35,390 --> 00:08:38,130 as it can, C and Python in particular. 178 00:08:38,130 --> 00:08:40,430 So it should feel familiar right from the start 179 00:08:40,430 --> 00:08:41,570 for a lot of you. 180 00:08:41,570 --> 00:08:44,570 To declare a variable, you use a "let" statement. 181 00:08:44,570 --> 00:08:46,850 Here we declare bunnies and initialize it 182 00:08:46,850 --> 00:08:48,590 to the value of 2. 183 00:08:48,590 --> 00:08:51,140 Rust is a strongly typed language. 184 00:08:51,140 --> 00:08:54,570 So where is the type annotation? 185 00:08:54,570 --> 00:08:59,250 Well, whenever the Rust compiler can figure out 186 00:08:59,250 --> 00:09:01,240 what the type is from the context, 187 00:09:01,240 --> 00:09:03,200 you can just leave it out. 188 00:09:03,200 --> 00:09:04,620 But when you do annotate the type, 189 00:09:04,620 --> 00:09:07,260 it looks like this, a colon after the variable name 190 00:09:07,260 --> 00:09:08,910 and then the type. 191 00:09:08,910 --> 00:09:11,940 Variables are immutable by default in Rust, which 192 00:09:11,940 --> 00:09:15,480 means unless you choose to make them mutable, 193 00:09:15,480 --> 00:09:17,640 you can't ever change their value. 194 00:09:17,640 --> 00:09:19,800 What happens if we try to change it anyway? 195 00:09:19,800 --> 00:09:23,530 Well, it gives us an error, this error, in fact. 196 00:09:23,530 --> 00:09:25,890 So here's our friendly compiler nudging us 197 00:09:25,890 --> 00:09:30,120 in the right direction with quite a bit of context. 198 00:09:30,120 --> 00:09:32,790 Here they said, make the variable on line 2 mutable. 199 00:09:32,790 --> 00:09:34,630 That's the core of what we're learning here. 200 00:09:34,630 --> 00:09:35,560 So let's do that. 201 00:09:35,560 --> 00:09:37,830 Let's go and put "mut" in front of bunnies, 202 00:09:37,830 --> 00:09:40,550 and this code will work just fine because now bunnies 203 00:09:40,550 --> 00:09:41,890 is a mutable variable. 204 00:09:41,890 --> 00:09:45,180 Now, why are variables immutable by default? 205 00:09:45,180 --> 00:09:47,700 I mean, it may seem confining at first, 206 00:09:47,700 --> 00:09:51,240 but let's think about what Rust cares about, safety. 207 00:09:51,240 --> 00:09:54,750 There are a lot of bugs that can't happen if a value never 208 00:09:54,750 --> 00:09:55,830 changes. 209 00:09:55,830 --> 00:09:58,440 Concurrency, well, data that never changes 210 00:09:58,440 --> 00:10:01,590 can be shared between multiple threads or coroutines 211 00:10:01,590 --> 00:10:03,390 without locks. 212 00:10:03,390 --> 00:10:06,780 And speed, well, the compiler can do extra optimizations 213 00:10:06,780 --> 00:10:08,860 on data it knows never changes. 214 00:10:08,860 --> 00:10:12,670 So that's why variables are immutable by default. 215 00:10:12,670 --> 00:10:14,280 Let's talk about scope. 216 00:10:14,280 --> 00:10:17,340 Variables have a scope, which is the place in the code 217 00:10:17,340 --> 00:10:19,230 that you're allowed to use them. 218 00:10:19,230 --> 00:10:23,070 The scope of a variable begins where it is created and extends 219 00:10:23,070 --> 00:10:24,360 to the end of the block. 220 00:10:24,360 --> 00:10:27,450 Along the way, it's accessible from nested blocks. 221 00:10:27,450 --> 00:10:31,020 A block is a collection of statements inside curly braces, 222 00:10:31,020 --> 00:10:32,640 that includes function bodies. 223 00:10:32,640 --> 00:10:36,870 In this example, x is defined in the main function's block. 224 00:10:36,870 --> 00:10:39,600 Then we create a nested block, and inside the nested block, 225 00:10:39,600 --> 00:10:40,860 we create y. 226 00:10:40,860 --> 00:10:45,600 And then we print x and y, which works just fine because x is 227 00:10:45,600 --> 00:10:48,190 accessible from nested blocks. 228 00:10:48,190 --> 00:10:50,610 Then the block ends, and y is immediately 229 00:10:50,610 --> 00:10:52,140 dropped at this point. 230 00:10:52,140 --> 00:10:53,430 There's no garbage collection. 231 00:10:53,430 --> 00:10:56,070 Values are always immediately dropped 232 00:10:56,070 --> 00:10:58,080 when they go out of scope, which means 233 00:10:58,080 --> 00:11:00,000 the last print won't work. 234 00:11:00,000 --> 00:11:03,660 But fear not, we discover this at compile time. 235 00:11:03,660 --> 00:11:07,380 The error message is pretty clear. 236 00:11:07,380 --> 00:11:11,280 Cannot find value y in this scope. 237 00:11:11,280 --> 00:11:14,610 So Rust guarantees memory safety at compile time. 238 00:11:14,610 --> 00:11:16,290 Let's talk about that. 239 00:11:16,290 --> 00:11:19,200 As part of that, variables must be initialized 240 00:11:19,200 --> 00:11:20,460 before you can use them. 241 00:11:20,460 --> 00:11:22,920 This code won't work because enigma 242 00:11:22,920 --> 00:11:25,890 has been declared but not initialized to a value 243 00:11:25,890 --> 00:11:27,850 before we try to use it. 244 00:11:27,850 --> 00:11:29,640 In fact, it won't even compile. 245 00:11:29,640 --> 00:11:34,440 We get the error use of possibly an initialized variable enigma. 246 00:11:34,440 --> 00:11:37,350 What if we might initialize enigma 247 00:11:37,350 --> 00:11:39,270 depending on some condition? 248 00:11:39,270 --> 00:11:42,960 Well, the compiler won't reason about the value of condition 249 00:11:42,960 --> 00:11:46,600 at compile time, even if it's a literal true or false. 250 00:11:46,600 --> 00:11:49,150 So conditional evaluation is handled at runtime. 251 00:11:49,150 --> 00:11:53,160 So the compiler can't guarantee that enigma will be initialized 252 00:11:53,160 --> 00:11:54,810 before it's used. 253 00:11:54,810 --> 00:11:56,490 But this works. 254 00:11:56,490 --> 00:11:59,760 The compiler can tell that enigma is guaranteed 255 00:11:59,760 --> 00:12:01,690 to be initialized in this case. 256 00:12:01,690 --> 00:12:04,800 And so, as long as the compiler can guarantee that something 257 00:12:04,800 --> 00:12:07,290 is safe, it'll let you do it. 258 00:12:07,290 --> 00:12:12,300 What if you tried the same thing in C? 259 00:12:12,300 --> 00:12:14,430 What if you declared a variable and then 260 00:12:14,430 --> 00:12:17,490 used it before initializing it? 261 00:12:17,490 --> 00:12:21,960 Welcome to the glorious realm of undefined behavior. 262 00:12:21,960 --> 00:12:24,300 On my Mac, I tried it, and I got the number 1. 263 00:12:24,300 --> 00:12:26,880 I'm not sure if that's just what was in memory or what, 264 00:12:26,880 --> 00:12:30,090 but your mileage may vary because your compiler can 265 00:12:30,090 --> 00:12:33,220 choose to do anything it wants to in this situation. 266 00:12:33,220 --> 00:12:35,940 So anyway, let's leave C and its craziness alone. 267 00:12:35,940 --> 00:12:37,860 Now it's time for functions. 268 00:12:37,860 --> 00:12:41,320 You have seen the main function quite a bit already. 269 00:12:41,320 --> 00:12:42,990 Let's talk about functions in general. 270 00:12:42,990 --> 00:12:46,680 Functions are defined using the fn keyword. 271 00:12:46,680 --> 00:12:47,970 It's pronounced "fun." 272 00:12:47,970 --> 00:12:50,670 The Rust style guide says to use snake case 273 00:12:50,670 --> 00:12:53,850 for function names, lowercase word separated by underscores. 274 00:12:53,850 --> 00:12:55,980 One awesome thing about Rust is that functions 275 00:12:55,980 --> 00:13:00,250 don't have to appear in the file before code that calls them. 276 00:13:00,250 --> 00:13:03,720 So feel free to leave main at the top of your main.rs 277 00:13:03,720 --> 00:13:04,710 file if you like. 278 00:13:04,710 --> 00:13:08,100 Hurray for more chronologically arranged source code. 279 00:13:08,100 --> 00:13:11,610 Systems programmers can have nice things too. 280 00:13:11,610 --> 00:13:14,700 Function parameters are always defined with name, colon, 281 00:13:14,700 --> 00:13:19,230 and type, and, of course, multiple parameters 282 00:13:19,230 --> 00:13:22,110 are separated by a comma. 283 00:13:22,110 --> 00:13:25,620 You specify the return type after the parameters 284 00:13:25,620 --> 00:13:29,320 by adding an arrow pointing to the return type. 285 00:13:29,320 --> 00:13:32,530 The arrow is a hyphen and a greater-than symbol. 286 00:13:32,530 --> 00:13:35,700 And then the body of the function is inside a block. 287 00:13:35,700 --> 00:13:38,220 You return a value from a function using return 288 00:13:38,220 --> 00:13:39,540 just like you'd expect. 289 00:13:39,540 --> 00:13:42,300 There's also a shorthand for returning values. 290 00:13:42,300 --> 00:13:46,050 If you leave the semicolon off of the last expression 291 00:13:46,050 --> 00:13:48,480 in a block, then that will be returned 292 00:13:48,480 --> 00:13:50,190 as the value of the block. 293 00:13:50,190 --> 00:13:55,350 In other words, this is the same as this. 294 00:13:55,350 --> 00:13:57,510 Whenever you are returning something 295 00:13:57,510 --> 00:13:59,550 at the end of a block, the shorter way 296 00:13:59,550 --> 00:14:03,330 is the preferred idiomatic Rust way. 297 00:14:03,330 --> 00:14:04,920 Calling the function looks the same 298 00:14:04,920 --> 00:14:07,260 as in most other languages. 299 00:14:07,260 --> 00:14:09,690 Finally, a single Rust function does not 300 00:14:09,690 --> 00:14:13,260 support variable numbers of arguments or different types 301 00:14:13,260 --> 00:14:14,490 for the same argument. 302 00:14:14,490 --> 00:14:16,920 But macros, such as print line, do. 303 00:14:16,920 --> 00:14:19,440 A macro call looks just like a function call, 304 00:14:19,440 --> 00:14:21,570 except the name of a macro always 305 00:14:21,570 --> 00:14:23,910 ends with an exclamation mark. 306 00:14:23,910 --> 00:14:28,200 There are four scalar types, integers, floats, Booleans, 307 00:14:28,200 --> 00:14:29,590 and characters. 308 00:14:29,590 --> 00:14:31,370 Let's go over integer types first. 309 00:14:31,370 --> 00:14:32,970 There's a lot of them. 310 00:14:32,970 --> 00:14:35,670 Unsigned integers start with u followed 311 00:14:35,670 --> 00:14:38,040 by the number of bits the integer has, 312 00:14:38,040 --> 00:14:41,940 consistent across all platforms, except for u size. 313 00:14:41,940 --> 00:14:44,940 u size is the size of the platform's pointer type 314 00:14:44,940 --> 00:14:49,690 and can represent every memory address in the process. 315 00:14:49,690 --> 00:14:51,060 It's also the type you'll usually 316 00:14:51,060 --> 00:14:55,440 use to index into an array or a vector, so you'll use that. 317 00:14:55,440 --> 00:14:58,140 Signed integers are the exact same story, 318 00:14:58,140 --> 00:15:01,560 except they use i for their prefix, i for integer, 319 00:15:01,560 --> 00:15:02,700 I presume. 320 00:15:02,700 --> 00:15:04,980 isize also has the same number of bits 321 00:15:04,980 --> 00:15:06,570 as the platform's pointer type. 322 00:15:06,570 --> 00:15:10,590 The maximum isize value is the upper bound 323 00:15:10,590 --> 00:15:12,240 of object in array size. 324 00:15:12,240 --> 00:15:14,130 This ensures the isize can be used 325 00:15:14,130 --> 00:15:16,410 to calculate differences between pointers 326 00:15:16,410 --> 00:15:18,840 and be able to address every single byte 327 00:15:18,840 --> 00:15:21,120 within a value like a struct. 328 00:15:21,120 --> 00:15:23,130 If you don't annotate an integer literal, 329 00:15:23,130 --> 00:15:27,270 it defaults to 32 because 32-bit integers are generally 330 00:15:27,270 --> 00:15:30,510 the fastest, even on 64-bit architectures. 331 00:15:30,510 --> 00:15:33,960 Now, just because the types have the same number of bits on all 332 00:15:33,960 --> 00:15:36,450 architectures doesn't mean all types are 333 00:15:36,450 --> 00:15:38,430 supported on all architectures. 334 00:15:38,430 --> 00:15:42,930 A 16-bit microcontroller might only support these types. 335 00:15:42,930 --> 00:15:44,850 Integer literals can be specified 336 00:15:44,850 --> 00:15:50,820 in a number of ways, which is particularly unsurprising. 337 00:15:50,820 --> 00:15:52,800 All except the last way can have any number 338 00:15:52,800 --> 00:15:57,150 of ignored underscores inside them to help with readability. 339 00:15:57,150 --> 00:15:59,970 Floating point types are straightforward, 340 00:15:59,970 --> 00:16:02,520 f32 has 32 bits of precision, and f64 341 00:16:02,520 --> 00:16:07,380 has 64 bits of precision. f64 is the default because it has more 342 00:16:07,380 --> 00:16:10,380 precision, but it's slow on 32-bit architectures, 343 00:16:10,380 --> 00:16:12,000 so careful with that. 344 00:16:12,000 --> 00:16:15,450 Floating point literals follow the IEEE-754 standard 345 00:16:15,450 --> 00:16:17,130 but basically look like this. 346 00:16:17,130 --> 00:16:19,260 No special suffix is required. 347 00:16:19,260 --> 00:16:21,960 Now for the Boolean type, the actual type 348 00:16:21,960 --> 00:16:23,160 is specified with bool. 349 00:16:23,160 --> 00:16:24,340 That's easy enough. 350 00:16:24,340 --> 00:16:28,740 The two Boolean literals are true and false, all lowercase. 351 00:16:28,740 --> 00:16:31,860 The character type is misnamed. 352 00:16:31,860 --> 00:16:34,320 Even though you specify it with char, 353 00:16:34,320 --> 00:16:37,350 it actually represents a single Unicode scalar 354 00:16:37,350 --> 00:16:39,870 value, which could be anything from a character 355 00:16:39,870 --> 00:16:43,260 of our alphabet, to a character of someone else's alphabet, 356 00:16:43,260 --> 00:16:48,630 to an idea graph, or a diacritic, or an emoji, 357 00:16:48,630 --> 00:16:50,310 or a non-printable Unicode control 358 00:16:50,310 --> 00:16:51,930 character that could represent anything 359 00:16:51,930 --> 00:16:54,420 from a sound to an action. 360 00:16:54,420 --> 00:16:56,520 A character is always 4 bytes, which, 361 00:16:56,520 --> 00:16:58,650 effectively, makes an array of characters 362 00:16:58,650 --> 00:17:02,370 a UCS-4 or UTF-32 string. 363 00:17:02,370 --> 00:17:04,830 Character literals are specified using single quotes, 364 00:17:04,830 --> 00:17:08,760 and most important of all, characters are fairly useless. 365 00:17:08,760 --> 00:17:11,310 Strings are UTF-8, and characters are not, 366 00:17:11,310 --> 00:17:13,380 so strings do not use characters. 367 00:17:13,380 --> 00:17:14,850 The source files are also UTF-8. 368 00:17:14,850 --> 00:17:16,480 So, chances are, when you want to deal 369 00:17:16,480 --> 00:17:17,940 with a single character, it's going 370 00:17:17,940 --> 00:17:20,610 to be a UTF-8 string and not a character. 371 00:17:20,610 --> 00:17:22,840 So we'll talk about strings in a little bit. 372 00:17:22,840 --> 00:17:26,100 But before that, let's talk about compound types. 373 00:17:26,100 --> 00:17:28,380 Compound types gather multiple values of other types 374 00:17:28,380 --> 00:17:30,000 into one type. 375 00:17:30,000 --> 00:17:32,190 The first compound type is the tuple. 376 00:17:32,190 --> 00:17:35,750 Tuples store multiple values of different types, 377 00:17:35,750 --> 00:17:39,270 use parentheses containing comma-separated values. 378 00:17:39,270 --> 00:17:41,400 The type annotation is pretty intuitive, 379 00:17:41,400 --> 00:17:44,940 parentheses surrounding comma-separated types. 380 00:17:44,940 --> 00:17:47,340 There are two ways to access the members of the tuple. 381 00:17:47,340 --> 00:17:49,950 The first way is to use dot syntax. 382 00:17:49,950 --> 00:17:52,590 Since the tuples fields have no names, 383 00:17:52,590 --> 00:17:55,590 you use their indices starting with 0. 384 00:17:55,590 --> 00:18:00,150 The second way to access members of a tuple is with a pattern. 385 00:18:00,150 --> 00:18:01,920 Please be aware that tuples currently 386 00:18:01,920 --> 00:18:05,760 have a maximum arity of 12, above which you can technically 387 00:18:05,760 --> 00:18:08,490 still use the tuple, but only with limited functionality. 388 00:18:08,490 --> 00:18:11,520 Arity means how many items are in the tuple. 389 00:18:11,520 --> 00:18:14,400 So this tuple type has an arity of four. 390 00:18:14,400 --> 00:18:16,440 So since the current maximum arity is 12, 391 00:18:16,440 --> 00:18:18,450 you can have a dozen elements in your tuple 392 00:18:18,450 --> 00:18:20,040 but not a baker's dozen, at least 393 00:18:20,040 --> 00:18:21,870 not if you want to use all the features. 394 00:18:21,870 --> 00:18:24,840 Arrays store multiple values of the same type. 395 00:18:24,840 --> 00:18:27,780 You can specify them literally with square brackets and commas 396 00:18:27,780 --> 00:18:32,400 or with a value and how many you want separated by a semicolon. 397 00:18:32,400 --> 00:18:34,740 Note that the type annotation for an array 398 00:18:34,740 --> 00:18:37,560 always uses the semicolon form, even 399 00:18:37,560 --> 00:18:41,460 when you specify all the literal values in the array. 400 00:18:41,460 --> 00:18:44,550 You index values in an array, as you would expect, 401 00:18:44,550 --> 00:18:45,630 with square brackets. 402 00:18:45,630 --> 00:18:47,230 What you would not expect, however, 403 00:18:47,230 --> 00:18:50,370 is that arrays are limited to a size of 32, above which they 404 00:18:50,370 --> 00:18:52,020 lose most of their functionality. 405 00:18:52,020 --> 00:18:55,120 Arrays live on the stack, by default, and are fixed size, 406 00:18:55,120 --> 00:18:58,230 so you will usually use vectors or slices 407 00:18:58,230 --> 00:19:00,170 of vectors instead of arrays. 408 00:19:00,170 --> 00:19:03,280 We'll talk about vectors in the collections section. 409 00:19:03,280 --> 00:19:06,750 Next up, control flow, which is awesome in Rust. 410 00:19:09,270 --> 00:19:11,970 If expressions are great, you don't need parentheses 411 00:19:11,970 --> 00:19:14,070 around the condition because everything 412 00:19:14,070 --> 00:19:18,970 between the "if" and the opening curly brace is the condition. 413 00:19:18,970 --> 00:19:21,480 The condition must evaluate to a Boolean 414 00:19:21,480 --> 00:19:24,270 because Rust does not like type coercion 415 00:19:24,270 --> 00:19:27,120 and mostly doesn't coerce types. 416 00:19:27,120 --> 00:19:29,190 If you want to chain a condition, 417 00:19:29,190 --> 00:19:31,530 you use else and if separately. 418 00:19:31,530 --> 00:19:34,300 And, of course, you can finish with else. 419 00:19:34,300 --> 00:19:36,850 If is an expression, not a statement. 420 00:19:36,850 --> 00:19:39,460 Statements don't return values, expressions 421 00:19:39,460 --> 00:19:44,540 do, meaning that we can change this code to this. 422 00:19:44,540 --> 00:19:47,800 So message is assigned the return value 423 00:19:47,800 --> 00:19:50,680 of the if expression. 424 00:19:50,680 --> 00:19:53,080 The braces are not optional, by the way. 425 00:19:53,080 --> 00:19:55,210 You always have to have them, which 426 00:19:55,210 --> 00:19:57,640 means you never hit that terrible situation that you 427 00:19:57,640 --> 00:20:01,510 do in C when you mean to add a second line to the branch 428 00:20:01,510 --> 00:20:05,800 of an if statement, but instead, your second line ends up 429 00:20:05,800 --> 00:20:10,060 being outside the branch body, and it happens unconditionally, 430 00:20:10,060 --> 00:20:13,630 despite your careful indentation. 431 00:20:13,630 --> 00:20:16,310 Isn't that just the worst? 432 00:20:16,310 --> 00:20:18,290 Let's talk about the unconditional loop. 433 00:20:18,290 --> 00:20:20,740 It turns out that if the compiler knows 434 00:20:20,740 --> 00:20:22,280 that a loop is unconditional, there's 435 00:20:22,280 --> 00:20:25,160 some pretty cool optimizations that it can do. 436 00:20:25,160 --> 00:20:28,880 Of course, even unconditional loops need to end, 437 00:20:28,880 --> 00:20:30,710 so you use the break statement for that. 438 00:20:30,710 --> 00:20:31,430 But wait. 439 00:20:31,430 --> 00:20:32,960 There's more. 440 00:20:32,960 --> 00:20:35,480 What if you want to break out of a nested loop? 441 00:20:35,480 --> 00:20:36,320 Can do. 442 00:20:36,320 --> 00:20:38,630 First, annotate the loop that you want 443 00:20:38,630 --> 00:20:40,220 to break out of with a label. 444 00:20:40,220 --> 00:20:42,200 This one is named bob. 445 00:20:42,200 --> 00:20:45,500 Labels have a strange syntax, single apostrophe 446 00:20:45,500 --> 00:20:48,020 beginning an identifier. 447 00:20:48,020 --> 00:20:51,830 Then tell break which loop you want to break out of. 448 00:20:51,830 --> 00:20:54,530 When this code hits the break statement in the inner loop, 449 00:20:54,530 --> 00:20:58,280 it'll break all the way out of the outermost bob loop. 450 00:20:58,280 --> 00:20:59,450 Continue is very similar. 451 00:20:59,450 --> 00:21:01,940 By itself, it continues the innermost loop. 452 00:21:01,940 --> 00:21:05,990 If you give it a label, then it continues the named loop. 453 00:21:05,990 --> 00:21:08,420 While loops have all the same behaviors 454 00:21:08,420 --> 00:21:10,340 as unconditional loops, except they 455 00:21:10,340 --> 00:21:14,100 terminate the loop when their condition evaluates to false. 456 00:21:14,100 --> 00:21:15,860 If you think about it, while loops 457 00:21:15,860 --> 00:21:18,860 are pretty much just syntactic sugar 458 00:21:18,860 --> 00:21:22,160 for putting a negated brake condition at the top 459 00:21:22,160 --> 00:21:24,150 of an unconditional loop. 460 00:21:24,150 --> 00:21:26,960 Now there's no do while construct in Rust. 461 00:21:26,960 --> 00:21:29,270 But it's pretty easy to rearrange this code 462 00:21:29,270 --> 00:21:30,020 to make it happen. 463 00:21:30,020 --> 00:21:33,270 Just put that condition down at the bottom of your loop. 464 00:21:33,270 --> 00:21:35,930 Voila, do while. 465 00:21:35,930 --> 00:21:37,550 Similar to modern scripting languages, 466 00:21:37,550 --> 00:21:42,260 Rust's for loop iterates over any iterable value. 467 00:21:42,260 --> 00:21:44,990 As an added bonus, the for loop can take a pattern 468 00:21:44,990 --> 00:21:47,480 to destructure the items it receives and bind 469 00:21:47,480 --> 00:21:50,840 the inside parts to variables local to the body of the 470 00:21:50,840 --> 00:21:51,830 for loop. 471 00:21:51,830 --> 00:21:55,460 Systems programmers can have nice things too. 472 00:21:55,460 --> 00:21:57,110 You'll probably want to use ranges 473 00:21:57,110 --> 00:21:58,640 with for loops at some point. 474 00:21:58,640 --> 00:22:01,790 The syntax for the range is two dots separating your start 475 00:22:01,790 --> 00:22:02,450 and end points. 476 00:22:02,450 --> 00:22:03,830 The start is inclusive. 477 00:22:03,830 --> 00:22:05,220 The end is exclusive. 478 00:22:05,220 --> 00:22:07,800 So this will count from 0 to 49. 479 00:22:07,800 --> 00:22:10,460 And if you use dot dot equals, then the end 480 00:22:10,460 --> 00:22:12,300 will be inclusive as well. 481 00:22:12,300 --> 00:22:14,990 So this will count from 0 to 50. 482 00:22:14,990 --> 00:22:17,260 String types, it's time. 483 00:22:20,500 --> 00:22:23,960 I'm going to warn you up front, here be dragons. 484 00:22:23,960 --> 00:22:25,420 I'll do me best to steer you right. 485 00:22:25,420 --> 00:22:31,300 There are at least six types of strings in Rust 486 00:22:31,300 --> 00:22:33,340 in the standard library alone. 487 00:22:33,340 --> 00:22:38,060 But we mostly care about two of them that overlap each other. 488 00:22:38,060 --> 00:22:40,240 The first is called a string slice, 489 00:22:40,240 --> 00:22:43,540 and you almost always see it as a borrowed string slice. 490 00:22:43,540 --> 00:22:45,670 We'll talk more about borrowing later. 491 00:22:45,670 --> 00:22:48,850 A literal string is always a string slice. 492 00:22:48,850 --> 00:22:52,470 A string slice is often referred to as a string, which 493 00:22:52,470 --> 00:22:54,970 can be really confusing when you learn that the other string 494 00:22:54,970 --> 00:22:58,630 type is a String with a capital S. 495 00:22:58,630 --> 00:23:01,060 The biggest difference between the two 496 00:23:01,060 --> 00:23:04,840 is that the data and a string slice can't be modified, 497 00:23:04,840 --> 00:23:08,110 but the data in a string can be modified. 498 00:23:08,110 --> 00:23:11,470 You'll often create a string by calling the to_string 499 00:23:11,470 --> 00:23:14,410 method on a string slice or by passing a string 500 00:23:14,410 --> 00:23:16,990 slice to string from. 501 00:23:16,990 --> 00:23:20,290 A string slice is internally made up of a pointer 502 00:23:20,290 --> 00:23:22,930 to some bytes and a length. 503 00:23:22,930 --> 00:23:27,100 A String is made up of a pointer to some bytes, a length, 504 00:23:27,100 --> 00:23:29,980 and a capacity that may be higher than what's currently 505 00:23:29,980 --> 00:23:31,700 being used. 506 00:23:31,700 --> 00:23:34,780 In other words, a string slice is a subset 507 00:23:34,780 --> 00:23:36,670 of a string in more ways than one, 508 00:23:36,670 --> 00:23:39,780 which is why they share a bunch of other characteristics. 509 00:23:39,780 --> 00:23:43,780 For example, both string types are valid UTF-8, 510 00:23:43,780 --> 00:23:46,420 by definition, by compiler enforcement, 511 00:23:46,420 --> 00:23:47,920 and by runtime checks. 512 00:23:47,920 --> 00:23:52,330 Also, strings cannot be indexed by character position. 513 00:23:52,330 --> 00:23:53,590 Why not? 514 00:23:53,590 --> 00:23:56,600 Well, because English is not the only language in the world. 515 00:23:56,600 --> 00:23:58,450 In fact, Google told me that there 516 00:23:58,450 --> 00:24:01,930 were over 6,900 living languages, 517 00:24:01,930 --> 00:24:03,700 and emojis on top of that. 518 00:24:03,700 --> 00:24:06,790 And they all seem to make their way into Unicode. 519 00:24:06,790 --> 00:24:11,690 And strings are Unicode, which means things get complicated. 520 00:24:11,690 --> 00:24:14,020 So let's look at Thai word [SPEAKING THAI].. 521 00:24:14,020 --> 00:24:17,710 Let's say that we wanted to get this thing. 522 00:24:17,710 --> 00:24:19,990 Looks like it should be index 3, right? 523 00:24:19,990 --> 00:24:24,430 Well, ultimately, this string is stored as a vector of 18 bytes. 524 00:24:24,430 --> 00:24:29,170 Would we get what we wanted if we indexed in by bytes? 525 00:24:29,170 --> 00:24:31,020 Well, not even close. 526 00:24:31,020 --> 00:24:31,690 I mean, come on. 527 00:24:31,690 --> 00:24:34,720 Unicode scalars in UTF-8 can be represented 528 00:24:34,720 --> 00:24:39,400 by 1, 2, 3, or 4 bytes. 529 00:24:39,400 --> 00:24:42,220 And you have to traverse the bytes in order 530 00:24:42,220 --> 00:24:45,970 to tell where one scalar ends and the next begins. 531 00:24:45,970 --> 00:24:49,360 In this case, every three bytes is the Unicode scalar. 532 00:24:49,360 --> 00:24:53,260 So if there were a way to index into the scalars, 533 00:24:53,260 --> 00:24:54,790 would we get what we want? 534 00:24:54,790 --> 00:24:57,910 Well, closer, but still off. 535 00:24:57,910 --> 00:25:02,050 Diacritics are one of the types of Unicode scalars 536 00:25:02,050 --> 00:25:05,050 that combine with other Unicode scalars 537 00:25:05,050 --> 00:25:07,660 to produce a different grapheme. 538 00:25:07,660 --> 00:25:11,990 And the grapheme is usually what we care about. 539 00:25:11,990 --> 00:25:15,190 So now you understand that graphemes decompose 540 00:25:15,190 --> 00:25:17,320 into variable amounts of scalars, which decompose 541 00:25:17,320 --> 00:25:18,970 into variable amounts of bytes. 542 00:25:18,970 --> 00:25:22,780 And as part of Rust's emphasis on speed, 543 00:25:22,780 --> 00:25:25,990 indexing operations on standard library collections 544 00:25:25,990 --> 00:25:29,660 are always guaranteed to be constant time operations. 545 00:25:29,660 --> 00:25:32,020 So you can't do that with strings 546 00:25:32,020 --> 00:25:35,710 because of the bytes, which are indexable, aren't guaranteed 547 00:25:35,710 --> 00:25:38,200 to be what people want when they index into a string. 548 00:25:38,200 --> 00:25:41,350 And the graphemes, which people do want, 549 00:25:41,350 --> 00:25:43,420 can only be retrieved after slowly 550 00:25:43,420 --> 00:25:45,250 examining a sequence of bytes. 551 00:25:45,250 --> 00:25:49,220 So when presented with the string, you have some options. 552 00:25:49,220 --> 00:25:51,040 You can use the bytes method to access 553 00:25:51,040 --> 00:25:55,720 the vector of UTF-8 bytes, which you can index into if you want 554 00:25:55,720 --> 00:25:57,760 since bytes are fixed size. 555 00:25:57,760 --> 00:26:00,280 This actually works fine for simple English text 556 00:26:00,280 --> 00:26:04,180 as long as you stick to the portion that overlaps Ascii. 557 00:26:04,180 --> 00:26:07,360 You can use the chars method to retrieve an iterator 558 00:26:07,360 --> 00:26:10,150 that you can use to iterate through the Unicode scalars. 559 00:26:10,150 --> 00:26:13,690 And finally, you can use a crate, or a project, 560 00:26:13,690 --> 00:26:17,710 like Unicode segmentation, which provides handy functions 561 00:26:17,710 --> 00:26:19,240 that return iterators that handle 562 00:26:19,240 --> 00:26:21,580 graphemes of various types. 563 00:26:21,580 --> 00:26:23,170 With each of these approaches, you 564 00:26:23,170 --> 00:26:25,270 know that if you can index into something, 565 00:26:25,270 --> 00:26:27,760 it will be a fast constant time operation, 566 00:26:27,760 --> 00:26:29,590 while if you iterate through something, 567 00:26:29,590 --> 00:26:32,320 it's going to process some variable number of bytes 568 00:26:32,320 --> 00:26:34,420 during each iteration of the loop. 569 00:26:34,420 --> 00:26:36,790 Hopefully, you can sidestep most of these issues 570 00:26:36,790 --> 00:26:39,370 by using one of the many helper methods created 571 00:26:39,370 --> 00:26:41,470 to manipulate strings. 572 00:26:41,470 --> 00:26:44,650 But if you do end up manually using one of the iterators, 573 00:26:44,650 --> 00:26:47,200 iterators have a handy method called nth 574 00:26:47,200 --> 00:26:49,180 that you can use in place of indexing. 575 00:26:49,180 --> 00:26:51,700 And now you know why you have to pick an iterator and use 576 00:26:51,700 --> 00:26:56,710 nth instead of being able to index into a string directly. 577 00:26:56,710 --> 00:26:57,790 Let's learn about structs. 578 00:27:00,410 --> 00:27:01,950 In other languages, you have classes. 579 00:27:01,950 --> 00:27:03,900 In Rust, you have structs. 580 00:27:03,900 --> 00:27:06,670 Structs can have data fields, methods, 581 00:27:06,670 --> 00:27:08,100 and associated functions. 582 00:27:08,100 --> 00:27:10,050 The syntax for the struct and its fields 583 00:27:10,050 --> 00:27:13,200 is the keyword struct and then the name 584 00:27:13,200 --> 00:27:16,650 of the struct in capital camel case, RedFox, in this case, 585 00:27:16,650 --> 00:27:20,370 then curly braces, and then the fields and their type 586 00:27:20,370 --> 00:27:23,070 annotations in a list separated by commas. 587 00:27:23,070 --> 00:27:27,000 And as a nice touch, you can end your last field with a comma 588 00:27:27,000 --> 00:27:29,190 as well so the compiler doesn't yell at you when 589 00:27:29,190 --> 00:27:31,440 you add another field and don't think to add 590 00:27:31,440 --> 00:27:33,270 a comma to the field before it. 591 00:27:33,270 --> 00:27:36,090 This feature is repeated in a lot of Rust constructs 592 00:27:36,090 --> 00:27:37,920 that use commas. 593 00:27:37,920 --> 00:27:40,650 Instantiating a struct is straightforward, though 594 00:27:40,650 --> 00:27:41,370 verbose. 595 00:27:41,370 --> 00:27:44,610 You need to specify a value for every single field by name. 596 00:27:44,610 --> 00:27:47,130 Typically, you would implement an associated function 597 00:27:47,130 --> 00:27:50,190 to use as a constructor to create a RedFox with default 598 00:27:50,190 --> 00:27:51,990 values and then call that. 599 00:27:51,990 --> 00:27:53,760 Methods and associated functions are 600 00:27:53,760 --> 00:27:56,340 defined in an implementation block 601 00:27:56,340 --> 00:27:58,950 that is separate from the struct definition. 602 00:27:58,950 --> 00:28:01,620 The implementation block starts with impl and then the name 603 00:28:01,620 --> 00:28:03,420 of the struct whose functions and methods 604 00:28:03,420 --> 00:28:05,250 you're going to implement. 605 00:28:05,250 --> 00:28:07,650 This is an associated function because it 606 00:28:07,650 --> 00:28:10,080 doesn't have a form of self as its first parameter. 607 00:28:10,080 --> 00:28:15,360 In many other languages, you'd call this a class method. 608 00:28:15,360 --> 00:28:17,130 Associated functions are often used 609 00:28:17,130 --> 00:28:19,230 like constructors in other languages, 610 00:28:19,230 --> 00:28:20,970 with new being the conventional name 611 00:28:20,970 --> 00:28:24,780 to use when you want to create a new struct with default values. 612 00:28:24,780 --> 00:28:28,080 Let's create our RedFox like this. 613 00:28:28,080 --> 00:28:30,450 The scope operator in Rust is double colons, 614 00:28:30,450 --> 00:28:33,450 and we'll use it to access parts of namespace 615 00:28:33,450 --> 00:28:37,110 like Rust constructs. 616 00:28:37,110 --> 00:28:39,210 Once you have an instantiated value, 617 00:28:39,210 --> 00:28:43,110 you get and set fields and call methods with dot syntax 618 00:28:43,110 --> 00:28:45,000 as you do in most languages. 619 00:28:45,000 --> 00:28:47,970 Methods are also defined in the implementation block. 620 00:28:47,970 --> 00:28:51,420 Methods always take some form of self as their first argument. 621 00:28:51,420 --> 00:28:53,040 At this point in the tutorial, for most 622 00:28:53,040 --> 00:28:55,710 of the other languages, I would go over class inheritance 623 00:28:55,710 --> 00:28:57,750 for a little bit, or struct inheritance, 624 00:28:57,750 --> 00:28:59,730 since that's what Rust calls its classes. 625 00:28:59,730 --> 00:29:01,770 It's a short discussion, though, because there 626 00:29:01,770 --> 00:29:04,050 is no struct inheritance. 627 00:29:04,050 --> 00:29:04,800 So, wait. 628 00:29:04,800 --> 00:29:07,170 Is Rust an object-oriented language or not? 629 00:29:07,170 --> 00:29:10,440 Well, it turns out that that's a religious war question 630 00:29:10,440 --> 00:29:14,070 because there's no universally accepted definition of what 631 00:29:14,070 --> 00:29:16,590 an object-oriented language is or isn't. 632 00:29:16,590 --> 00:29:21,360 And since the Rust community doesn't do religious wars, 633 00:29:21,360 --> 00:29:23,290 nobody really cares what the answer is. 634 00:29:23,290 --> 00:29:25,490 The real question is, why doesn't Rust 635 00:29:25,490 --> 00:29:26,610 have struct inheritance? 636 00:29:26,610 --> 00:29:28,920 The answer is because they chose a better way 637 00:29:28,920 --> 00:29:32,100 to solve the problem that we wish inheritance solved. 638 00:29:32,100 --> 00:29:33,210 Traits. 639 00:29:33,210 --> 00:29:35,640 Traits are similar to interfaces in other languages, 640 00:29:35,640 --> 00:29:36,930 and they're really cool. 641 00:29:36,930 --> 00:29:40,290 Rust takes the composition over inheritance approach. 642 00:29:40,290 --> 00:29:42,660 Remember our RedFox struct? 643 00:29:42,660 --> 00:29:44,910 Let's make a trait called noisy. 644 00:29:44,910 --> 00:29:47,290 Traits define required behavior. 645 00:29:47,290 --> 00:29:49,740 In other words, functions and methods that a struct 646 00:29:49,740 --> 00:29:53,490 must implement if it wants to have that trait. 647 00:29:53,490 --> 00:29:55,620 The noisy trait specifies that a struct 648 00:29:55,620 --> 00:29:58,920 must have a method named get_noise 649 00:29:58,920 --> 00:30:02,670 that returns a borrowed string slice if the struct wants 650 00:30:02,670 --> 00:30:04,540 to be noisy. 651 00:30:04,540 --> 00:30:08,610 So let's add an implementation of the noisy trait for RedFox. 652 00:30:08,610 --> 00:30:10,290 Let's take a look at how this works. 653 00:30:10,290 --> 00:30:14,310 We implement the noisy trait for the RedFox struct, 654 00:30:14,310 --> 00:30:17,100 and our implementation of the required get_noise method 655 00:30:17,100 --> 00:30:19,500 is meow? 656 00:30:19,500 --> 00:30:21,300 Which is all great because now we 657 00:30:21,300 --> 00:30:23,340 can start writing generic functions that 658 00:30:23,340 --> 00:30:26,260 accept any value that implements the trait. 659 00:30:26,260 --> 00:30:29,340 So this function takes an item of type T, 660 00:30:29,340 --> 00:30:31,650 which is defined to be anything that 661 00:30:31,650 --> 00:30:34,200 implements the noisy trait. 662 00:30:34,200 --> 00:30:37,650 The function can use any behavior on item 663 00:30:37,650 --> 00:30:40,260 that the noisy trait defines. 664 00:30:40,260 --> 00:30:42,450 So now we have a generic function 665 00:30:42,450 --> 00:30:47,280 that can take any type as long as it is noisy. 666 00:30:47,280 --> 00:30:49,140 So that's pretty cool. 667 00:30:49,140 --> 00:30:53,460 As long as one of either the trait or the struct 668 00:30:53,460 --> 00:30:57,510 is defined in your project, then you can implement 669 00:30:57,510 --> 00:31:01,600 any trait for any struct. 670 00:31:01,600 --> 00:31:02,310 Think about that. 671 00:31:02,310 --> 00:31:06,990 That means you can implement your traits, on any types, 672 00:31:06,990 --> 00:31:10,930 from anywhere, including built-in, standard library, 673 00:31:10,930 --> 00:31:12,900 or some third-party package. 674 00:31:12,900 --> 00:31:16,560 And on your structs, you can implement any trait 675 00:31:16,560 --> 00:31:18,390 from anywhere. 676 00:31:18,390 --> 00:31:21,540 Here I've implemented the noisy trait for the built-in type 677 00:31:21,540 --> 00:31:23,400 u8, which is a byte. 678 00:31:23,400 --> 00:31:25,590 So a generic print noise function 679 00:31:25,590 --> 00:31:28,750 now works fine with bytes. 680 00:31:28,750 --> 00:31:30,960 So let's go through an example of where traits really 681 00:31:30,960 --> 00:31:31,900 seem to shine. 682 00:31:31,900 --> 00:31:35,250 Let's say we have a game with a goose, a Pegasus, and a horse. 683 00:31:35,250 --> 00:31:37,710 These have several attributes in common. 684 00:31:37,710 --> 00:31:39,210 These two can fly. 685 00:31:39,210 --> 00:31:40,590 These two can be ridden. 686 00:31:40,590 --> 00:31:42,810 And these two explode. 687 00:31:42,810 --> 00:31:44,520 You can see how it could get really 688 00:31:44,520 --> 00:31:47,610 tricky to use inheritance to define the correct behavior 689 00:31:47,610 --> 00:31:49,920 that each final value needs to have. 690 00:31:49,920 --> 00:31:52,170 But it's pretty straightforward with traits. 691 00:31:52,170 --> 00:31:54,870 The goose implements the fly and explode traits. 692 00:31:54,870 --> 00:31:57,060 The Pegasus implements the fly and ride traits, 693 00:31:57,060 --> 00:31:59,590 and the horse implements the ride and explode traits. 694 00:31:59,590 --> 00:32:01,070 And we're all happy. 695 00:32:01,070 --> 00:32:03,940 I will call out that you can't define fields 696 00:32:03,940 --> 00:32:05,020 as part of traits. 697 00:32:05,020 --> 00:32:07,450 That may be added in the future some time 698 00:32:07,450 --> 00:32:09,700 if someone can figure out the right way to do it. 699 00:32:09,700 --> 00:32:11,530 In the meantime, the workaround is 700 00:32:11,530 --> 00:32:13,870 to define setter and getter methods in your trait 701 00:32:13,870 --> 00:32:16,250 if you want traits to have data. 702 00:32:16,250 --> 00:32:18,490 So let's go over some collections now. 703 00:32:22,080 --> 00:32:25,830 Vector is a generic collection that holds a bunch of one type 704 00:32:25,830 --> 00:32:28,140 and is useful where you'd use lists 705 00:32:28,140 --> 00:32:30,430 or arrays in other languages. 706 00:32:30,430 --> 00:32:33,990 It's the most commonly used collection by far. 707 00:32:33,990 --> 00:32:36,210 HashMap is a generic collection where 708 00:32:36,210 --> 00:32:39,120 you specify a type for the key and a type for the value, 709 00:32:39,120 --> 00:32:41,040 and you access the values by key. 710 00:32:41,040 --> 00:32:43,600 In some languages, you would call it a dictionary. 711 00:32:43,600 --> 00:32:45,180 The whole point of a hash map is to be 712 00:32:45,180 --> 00:32:47,580 able to insert, look up, and remove values 713 00:32:47,580 --> 00:32:50,200 by key in constant time. 714 00:32:50,200 --> 00:32:51,780 There are a bunch of other collections 715 00:32:51,780 --> 00:32:53,910 that I don't have time to talk about today. 716 00:32:53,910 --> 00:32:55,620 You should check them out later if you're 717 00:32:55,620 --> 00:32:57,030 interested in using them. 718 00:32:57,030 --> 00:32:58,280 Let's learn about enums. 719 00:32:58,280 --> 00:33:02,470 Enums in Rust are more like algebraic data types in Haskell 720 00:33:02,470 --> 00:33:04,440 than C-like enums. 721 00:33:04,440 --> 00:33:07,440 You specify an enum with a keyword enum, 722 00:33:07,440 --> 00:33:09,870 the name of the enum with capital camel case, 723 00:33:09,870 --> 00:33:13,170 and the names of the variants in a block. 724 00:33:13,170 --> 00:33:15,720 You can stop there if you want and use it just 725 00:33:15,720 --> 00:33:19,770 like that, in which case, it sort of is like an enum in C. 726 00:33:19,770 --> 00:33:22,080 Just namespace into the enum, and away you go. 727 00:33:22,080 --> 00:33:24,570 However, the real power of a Rust enum 728 00:33:24,570 --> 00:33:27,840 comes from associating data with the variants. 729 00:33:27,840 --> 00:33:30,840 You can always have a named variant with no data. 730 00:33:30,840 --> 00:33:34,560 A variant can have a single type of data, a tuple of data, 731 00:33:34,560 --> 00:33:36,520 or an anonymous struct of data. 732 00:33:36,520 --> 00:33:37,140 Let's be clear. 733 00:33:37,140 --> 00:33:41,280 An enum is sort of like a union in C, only so much better. 734 00:33:41,280 --> 00:33:43,200 If you create an enum, the value can 735 00:33:43,200 --> 00:33:45,870 be any one of these variants. 736 00:33:45,870 --> 00:33:48,030 So, for example, your dispenser item 737 00:33:48,030 --> 00:33:51,450 could be an empty with no data associated with it, 738 00:33:51,450 --> 00:33:53,190 but you can tell that it's an empty. 739 00:33:53,190 --> 00:33:56,940 Or it could be an ammo with 69 as its value. 740 00:33:56,940 --> 00:34:01,090 Or it could be things with a string and a 7 in there. 741 00:34:01,090 --> 00:34:04,150 Or it could be a place with x and y-coordinates. 742 00:34:04,150 --> 00:34:07,930 It can be any one of these things but only one at a time. 743 00:34:07,930 --> 00:34:10,860 Even better, you can implement functions and methods 744 00:34:10,860 --> 00:34:12,570 for an enum. 745 00:34:12,570 --> 00:34:16,510 You can also use enums with generics. 746 00:34:16,510 --> 00:34:19,450 Option is a generic enum in the standard library 747 00:34:19,450 --> 00:34:21,160 that you'll use all the time. 748 00:34:21,160 --> 00:34:24,390 It represents when you either have something or you don't. 749 00:34:24,390 --> 00:34:26,920 You use patterns to examine enums. 750 00:34:26,920 --> 00:34:29,140 If you want to check for a single variant, 751 00:34:29,140 --> 00:34:32,110 you use the if let expression. 752 00:34:32,110 --> 00:34:36,790 if let takes a pattern that will match one of the variants. 753 00:34:36,790 --> 00:34:39,520 If the pattern does match, then the condition is true, 754 00:34:39,520 --> 00:34:41,710 and the variables inside the pattern 755 00:34:41,710 --> 00:34:45,620 are created for the scope of the if let block. 756 00:34:45,620 --> 00:34:49,220 If the pattern doesn't match, then the condition is false. 757 00:34:49,220 --> 00:34:52,210 So this is pretty handy if you care about one variant matching 758 00:34:52,210 --> 00:34:55,450 or not but not as great if you need to handle 759 00:34:55,450 --> 00:34:56,860 all the variants at once. 760 00:34:56,860 --> 00:34:59,780 In that case, you use the match expression, 761 00:34:59,780 --> 00:35:02,560 which is match and then the variable, whose type supports 762 00:35:02,560 --> 00:35:03,960 matching like an enum. 763 00:35:03,960 --> 00:35:05,340 The body of the match, in braces, 764 00:35:05,340 --> 00:35:07,540 is where you specify patterns followed 765 00:35:07,540 --> 00:35:10,600 by double arrows, which are equal signs followed by greater 766 00:35:10,600 --> 00:35:14,320 than symbols, pointing to an expression that also represents 767 00:35:14,320 --> 00:35:17,080 the return value of that arm of the match. 768 00:35:17,080 --> 00:35:21,520 Matches are like switch statements on serious steroids. 769 00:35:21,520 --> 00:35:23,830 Match expressions require you to write a branch 770 00:35:23,830 --> 00:35:25,770 for every possible outcome. 771 00:35:25,770 --> 00:35:27,850 In other words, the patterns in a match expression 772 00:35:27,850 --> 00:35:29,590 must be exhaustive. 773 00:35:29,590 --> 00:35:31,840 A single underscore all by itself 774 00:35:31,840 --> 00:35:34,570 represents a wild card pattern that matches anything. 775 00:35:34,570 --> 00:35:38,260 So you can use that as a default or an anything else branch. 776 00:35:38,260 --> 00:35:40,540 Note that even though you'll often see blocks 777 00:35:40,540 --> 00:35:42,100 as the expression for a branch arm, 778 00:35:42,100 --> 00:35:44,710 any expression will do, including things like function 779 00:35:44,710 --> 00:35:46,940 calls and bare values. 780 00:35:46,940 --> 00:35:49,240 So if you actually use the return value 781 00:35:49,240 --> 00:35:51,890 of an expression that ends in a curly brace, 782 00:35:51,890 --> 00:35:54,820 so if match if let, et cetera, then you 783 00:35:54,820 --> 00:35:58,150 need to put a semicolon after the closing brace. 784 00:35:58,150 --> 00:36:03,340 Finally, it's time to talk about ownership. 785 00:36:03,340 --> 00:36:06,130 There are three rules to ownership, 786 00:36:06,130 --> 00:36:09,640 and this is why I came to Rust. 787 00:36:09,640 --> 00:36:12,100 First, each value has an owner. 788 00:36:12,100 --> 00:36:15,460 There is no value in memory, no data that doesn't 789 00:36:15,460 --> 00:36:17,870 have a variable that owns it. 790 00:36:17,870 --> 00:36:22,780 Second, there is only one owner of a value. 791 00:36:22,780 --> 00:36:25,100 No variables share ownership. 792 00:36:25,100 --> 00:36:28,330 Other variables may borrow the value, which 793 00:36:28,330 --> 00:36:29,750 we'll talk about in just a minute, 794 00:36:29,750 --> 00:36:32,320 but only one variable owns it. 795 00:36:32,320 --> 00:36:35,320 And three, when the owner goes out of scope, 796 00:36:35,320 --> 00:36:38,660 the value gets dropped immediately. 797 00:36:38,660 --> 00:36:40,360 So let's see ownership in action. 798 00:36:40,360 --> 00:36:46,030 Let's create a string s1 and then create another variable s2 799 00:36:46,030 --> 00:36:48,650 and assign s1's value to it. 800 00:36:48,650 --> 00:36:53,260 What happens to this string is not a copy. 801 00:36:53,260 --> 00:36:56,980 At this point, the value for s1 is moved to s2 802 00:36:56,980 --> 00:37:00,250 because only one variable can own the value. 803 00:37:00,250 --> 00:37:03,130 If we try to go ahead and use s1 after this point, 804 00:37:03,130 --> 00:37:05,670 we get a compiler error. 805 00:37:05,670 --> 00:37:07,920 Borrow of moved value s1. 806 00:37:07,920 --> 00:37:09,770 So what's going on here? 807 00:37:09,770 --> 00:37:11,850 Well, we've got stack and heap sections of memory. 808 00:37:11,850 --> 00:37:13,530 Just a super quick refresher. 809 00:37:13,530 --> 00:37:15,420 The stack stores values in order, 810 00:37:15,420 --> 00:37:17,680 which you can do because values are always fixed size. 811 00:37:17,680 --> 00:37:19,860 And the last value in is the first value out, 812 00:37:19,860 --> 00:37:21,840 which all tends to be very fast because it's 813 00:37:21,840 --> 00:37:23,550 so compact and predictable. 814 00:37:23,550 --> 00:37:26,940 The heap, in contrast, stores values all over the place, 815 00:37:26,940 --> 00:37:28,950 and values tend to get resized and don't 816 00:37:28,950 --> 00:37:30,840 get dropped in any order that correspond 817 00:37:30,840 --> 00:37:32,580 to when and where they were created, 818 00:37:32,580 --> 00:37:35,520 which tends to make using the heap slower than the stack. 819 00:37:35,520 --> 00:37:38,850 Well, what does that have to do with a value being moved? 820 00:37:38,850 --> 00:37:40,560 Let's walk through it. 821 00:37:40,560 --> 00:37:42,510 First, we create s1. 822 00:37:42,510 --> 00:37:45,600 A pointer, a length, and a capacity 823 00:37:45,600 --> 00:37:47,280 get pushed onto the stack. 824 00:37:47,280 --> 00:37:50,280 The value of capacity, in this case, is 3, the value of length 825 00:37:50,280 --> 00:37:54,210 is 3, and the pointer points to some newly allocated 826 00:37:54,210 --> 00:37:56,460 bytes on the heap. 827 00:37:56,460 --> 00:38:01,530 This, altogether, is the value of this string s1. 828 00:38:01,530 --> 00:38:05,670 Then we move s1's value to s2 because we can only 829 00:38:05,670 --> 00:38:06,810 have one owner. 830 00:38:06,810 --> 00:38:08,590 It works like this. 831 00:38:08,590 --> 00:38:12,600 The pointer, length, and capacity all get copied from s1 832 00:38:12,600 --> 00:38:15,840 and pushed its new values on the stack as part of s2. 833 00:38:15,840 --> 00:38:18,120 And if we stopped here, then we wouldn't 834 00:38:18,120 --> 00:38:20,850 have memory safety, which is why Rust immediately 835 00:38:20,850 --> 00:38:22,740 invalidates s1. 836 00:38:22,740 --> 00:38:24,150 It's more than a shallow copy. 837 00:38:24,150 --> 00:38:28,920 It's a move, which is why we can't use s1 anymore. 838 00:38:28,920 --> 00:38:31,500 The value has moved to s2. 839 00:38:31,500 --> 00:38:34,050 What if we don't want to move the value, 840 00:38:34,050 --> 00:38:35,970 but we want to copy it instead. 841 00:38:35,970 --> 00:38:39,030 To make a copy of s1, we would call the clone method. 842 00:38:39,030 --> 00:38:41,350 Well, why is it called clone instead of copy? 843 00:38:41,350 --> 00:38:43,140 Let me explain what it does under the hood, 844 00:38:43,140 --> 00:38:44,550 and then I'll tell you. 845 00:38:44,550 --> 00:38:49,020 Clone performs the same initial copy of the stack 846 00:38:49,020 --> 00:38:51,300 but then also copies the heap data 847 00:38:51,300 --> 00:38:55,420 and adjusts s2's pointer to point to it. 848 00:38:55,420 --> 00:38:58,650 So in both the move and the clone situations, 849 00:38:58,650 --> 00:39:00,150 the three rules are satisfied. 850 00:39:00,150 --> 00:39:04,740 1, the values have owners, and 2, they only have one owner, 851 00:39:04,740 --> 00:39:07,140 and 3, when the variables go out of scope, 852 00:39:07,140 --> 00:39:09,010 the values will be immediately dropped. 853 00:39:09,010 --> 00:39:11,220 They don't have to worry about someone else using it. 854 00:39:11,220 --> 00:39:14,640 The stack and heap data, if there is heap data, 855 00:39:14,640 --> 00:39:16,950 together make up a value. 856 00:39:16,950 --> 00:39:20,850 Rust reserves the term copy for when only the stack data is 857 00:39:20,850 --> 00:39:21,960 being copied. 858 00:39:21,960 --> 00:39:25,150 If there's heap data and pointer updates involved, 859 00:39:25,150 --> 00:39:27,150 then we use the term clone. 860 00:39:27,150 --> 00:39:30,750 In other languages, you might call clone a deep copy. 861 00:39:30,750 --> 00:39:33,060 There's a special trait called copy. 862 00:39:33,060 --> 00:39:35,730 If your type is copy, then it will 863 00:39:35,730 --> 00:39:39,120 be copied instead of moved in a move situation. 864 00:39:39,120 --> 00:39:41,190 This makes sense for small values 865 00:39:41,190 --> 00:39:42,870 that fit entirely on the stack, which 866 00:39:42,870 --> 00:39:45,960 is why the simple primitive types, like integers, floats, 867 00:39:45,960 --> 00:39:49,230 Booleans, and chars, implement copy. 868 00:39:49,230 --> 00:39:53,490 If a type uses the heap at all, then it can't be copied. 869 00:39:53,490 --> 00:39:57,150 You can opt in to implementing copy with your own types 870 00:39:57,150 --> 00:40:02,120 if you make your type of only other copy types. 871 00:40:02,120 --> 00:40:04,370 When a value is dropped, that means 872 00:40:04,370 --> 00:40:07,700 that the destructor if there is one, is immediately run, 873 00:40:07,700 --> 00:40:09,620 the heap portion is immediately freed, 874 00:40:09,620 --> 00:40:12,110 and the stock portion is immediately popped. 875 00:40:12,110 --> 00:40:16,400 So no leaks, no dangling pointers, yes, 876 00:40:16,400 --> 00:40:18,530 happy programmer. 877 00:40:18,530 --> 00:40:22,760 Another move situation, let's start with the same string 878 00:40:22,760 --> 00:40:26,870 and make a function that takes a string and returns nothing. 879 00:40:26,870 --> 00:40:29,420 If we pass s1 to the function, s1 880 00:40:29,420 --> 00:40:32,810 is moved into the local variable in do_stuff, 881 00:40:32,810 --> 00:40:36,890 our function, which means we can't use s1 anymore 882 00:40:36,890 --> 00:40:38,510 because it got moved. 883 00:40:38,510 --> 00:40:39,930 So what do we do? 884 00:40:39,930 --> 00:40:42,630 Well, one option is to move it back when we're done. 885 00:40:42,630 --> 00:40:46,670 We'll just make s1 mutable, add a return type to do_stuff, 886 00:40:46,670 --> 00:40:50,180 and then return s, which gets moved back out of the function 887 00:40:50,180 --> 00:40:52,930 and used to reinitialize s1. 888 00:40:52,930 --> 00:40:53,930 That sounds like a pain. 889 00:40:53,930 --> 00:40:55,560 That's not what we want to do, usually. 890 00:40:55,560 --> 00:40:57,830 Passing ownership of a value to a function 891 00:40:57,830 --> 00:41:00,410 usually means that the function is going 892 00:41:00,410 --> 00:41:02,420 to consume the passed-in value. 893 00:41:02,420 --> 00:41:05,310 For most other cases, you should use references, 894 00:41:05,310 --> 00:41:10,560 which is why it's time to talk about references and borrowing. 895 00:41:10,560 --> 00:41:14,750 Instead of moving our variable, let's use a reference. 896 00:41:14,750 --> 00:41:16,720 Here's our do_stuff function again, 897 00:41:16,720 --> 00:41:20,390 only this time, it takes a reference to a string. 898 00:41:20,390 --> 00:41:22,840 The ampersand before the type indicates a reference 899 00:41:22,840 --> 00:41:24,130 to a type. 900 00:41:24,130 --> 00:41:27,880 When we call do_stuff, we pass it a reference to s1. 901 00:41:27,880 --> 00:41:29,740 There's that ampersand again. 902 00:41:29,740 --> 00:41:33,190 And s1 retains ownership of the value. 903 00:41:33,190 --> 00:41:36,760 Do_stuff borrows a reference to the value. 904 00:41:36,760 --> 00:41:40,150 After the function call, we can use s1 like normal 905 00:41:40,150 --> 00:41:42,790 because the value never moved. 906 00:41:42,790 --> 00:41:46,270 Under the hood, when we create a reference to s1, 907 00:41:46,270 --> 00:41:48,730 Rust creates a pointer to s1. 908 00:41:48,730 --> 00:41:51,670 But you'll almost never talk about pointers in Rust 909 00:41:51,670 --> 00:41:54,280 because the language automatically handles 910 00:41:54,280 --> 00:41:57,370 their creation and destruction for the most part 911 00:41:57,370 --> 00:41:59,140 and makes sure that they're always valid 912 00:41:59,140 --> 00:42:01,720 as well using a concept called lifetimes. 913 00:42:01,720 --> 00:42:03,760 Lifetimes can be summed up as a rule 914 00:42:03,760 --> 00:42:06,140 that references must always be valid, 915 00:42:06,140 --> 00:42:09,250 which means the compiler won't let you create a reference that 916 00:42:09,250 --> 00:42:11,590 outlives the data that it's referencing. 917 00:42:11,590 --> 00:42:14,810 And you can never point to null. 918 00:42:14,810 --> 00:42:18,380 References default to immutable even if the value being 919 00:42:18,380 --> 00:42:20,030 referenced is mutable. 920 00:42:20,030 --> 00:42:23,330 But if we make a mutable reference to a mutable value, 921 00:42:23,330 --> 00:42:26,210 then we can use the reference to change the value. 922 00:42:26,210 --> 00:42:30,170 The syntax for a mutable reference is a little special. 923 00:42:30,170 --> 00:42:34,430 Ampersand mute space variable or type. 924 00:42:34,430 --> 00:42:38,400 So let's stop and go over what references look like again. 925 00:42:38,400 --> 00:42:41,480 So here's a variable, immutable reference 926 00:42:41,480 --> 00:42:47,200 to a variable, mutable reference to a variable, type, 927 00:42:47,200 --> 00:42:51,850 immutable reference to a type, mutable reference to a type. 928 00:42:51,850 --> 00:42:54,190 Naturally, since references are implemented 929 00:42:54,190 --> 00:42:55,990 via pointers, which are dangerous, 930 00:42:55,990 --> 00:42:59,650 Rust has a special rule to keep us safe. 931 00:42:59,650 --> 00:43:02,440 At any given time, you can have either 932 00:43:02,440 --> 00:43:07,810 exactly one mutable reference or any number 933 00:43:07,810 --> 00:43:09,760 of immutable references. 934 00:43:09,760 --> 00:43:12,850 This rule applies across all threads. 935 00:43:12,850 --> 00:43:15,160 So when you consider that references to a variable 936 00:43:15,160 --> 00:43:17,500 may exist in different threads, it 937 00:43:17,500 --> 00:43:19,150 makes it pretty obvious why it's not 938 00:43:19,150 --> 00:43:22,660 safe to have multiple mutable references 939 00:43:22,660 --> 00:43:25,030 to the same variable, at the same time, 940 00:43:25,030 --> 00:43:27,610 without some type of locking. 941 00:43:27,610 --> 00:43:29,290 All these rules I've been talking about 942 00:43:29,290 --> 00:43:32,260 are enforced by the compiler, and by enforced, I 943 00:43:32,260 --> 00:43:35,320 mean, oh, I mean compiler errors, lots 944 00:43:35,320 --> 00:43:36,580 of compiler errors. 945 00:43:36,580 --> 00:43:39,940 And at first, you're like, I hate the compiler. 946 00:43:39,940 --> 00:43:41,860 It just keeps giving me errors. 947 00:43:41,860 --> 00:43:43,360 But then, as you get the hang of it, 948 00:43:43,360 --> 00:43:46,810 you realize you don't get mysterious segfaults anymore. 949 00:43:46,810 --> 00:43:50,330 And the error messages are really pretty nice. 950 00:43:50,330 --> 00:43:52,160 I mean, they're informative and everything. 951 00:43:52,160 --> 00:43:55,030 And if the code compiles, it works. 952 00:43:55,030 --> 00:43:58,870 And that's an amazing feeling. 953 00:43:58,870 --> 00:44:01,630 That's all the toys I could fit in the toy box today. 954 00:44:01,630 --> 00:44:02,570 We're at time. 955 00:44:02,570 --> 00:44:04,880 So where do you go to learn more? 956 00:44:04,880 --> 00:44:08,440 There is an entire set of documentation and a community 957 00:44:08,440 --> 00:44:12,910 to explore it Rust-lang.org, some excellent books, 958 00:44:12,910 --> 00:44:15,070 you could take my half day course on Safari 959 00:44:15,070 --> 00:44:18,760 or at conferences like OSCON, you could poke around with some 960 00:44:18,760 --> 00:44:22,450 fun open source Rust projects on my GitHub account 961 00:44:22,450 --> 00:44:23,770 or in the community. 962 00:44:23,770 --> 00:44:25,810 My username is cleancut at GitHub. 963 00:44:25,810 --> 00:44:27,700 You've been a wonderful audience. 964 00:44:27,700 --> 00:44:31,190 It's been my absolute pleasure to be here with you today. 965 00:44:31,190 --> 00:44:32,290 Thank you very much. 966 00:44:32,290 --> 00:44:35,040 [APPLAUSE]