1 00:00:02,440 --> 00:00:03,579 Enums and structs 2 00:00:03,580 --> 00:00:05,509 are how we define the data that makes 3 00:00:05,510 --> 00:00:06,760 up custom types. 4 00:00:07,400 --> 00:00:09,399 Methods are how we define behavior 5 00:00:09,400 --> 00:00:10,690 on custom types. 6 00:00:12,830 --> 00:00:14,839 Methods are similar to functions, which 7 00:00:14,840 --> 00:00:16,450 we covered in module 5. 8 00:00:17,560 --> 00:00:19,419 Methods are defined either in the context 9 00:00:19,420 --> 00:00:21,529 of an enum that we talked about in module 10 00:00:21,530 --> 00:00:22,230 7 11 00:00:22,810 --> 00:00:24,900 or a struct from module 8. 12 00:00:25,570 --> 00:00:27,870 Review these modules to get ready for this one. 13 00:00:30,160 --> 00:00:32,228 In this module, we'll take a look at when 14 00:00:32,229 --> 00:00:33,420 methods are useful. 15 00:00:34,090 --> 00:00:35,739 We'll cover how to define methods 16 00:00:35,740 --> 00:00:37,560 and then show how to call methods. 17 00:00:38,380 --> 00:00:40,419 We'll take a brief aside to mention associated 18 00:00:40,420 --> 00:00:42,429 functions and how they're different from regular 19 00:00:42,430 --> 00:00:43,950 functions and methods. 20 00:00:44,530 --> 00:00:46,479 We'll wrap up by talking about the difference 21 00:00:46,480 --> 00:00:48,489 between methods that only need to read 22 00:00:48,490 --> 00:00:50,220 data from the type they're defined on 23 00:00:50,380 --> 00:00:52,359 versus methods that need to be able to modify 24 00:00:52,360 --> 00:00:53,340 the data too. 25 00:00:56,040 --> 00:00:58,070 Let's start with when methods are useful. 26 00:00:59,040 --> 00:01:00,869 Let's take a look at the HockeyPlayer struct 27 00:01:00,870 --> 00:01:02,480 we defined in module 8. 28 00:01:03,300 --> 00:01:04,760 With just this definition, 29 00:01:04,950 --> 00:01:06,809 we can create an instance, read from 30 00:01:06,810 --> 00:01:08,759 its fields, change the values 31 00:01:08,760 --> 00:01:10,660 in the fields if the instance is mutable, 32 00:01:10,920 --> 00:01:11,890 but that's about it. 33 00:01:13,970 --> 00:01:15,889 We'd like to model what happens when a player 34 00:01:15,890 --> 00:01:17,470 shoots the puck at the goal. 35 00:01:17,960 --> 00:01:19,819 So, let's start by defining a function named 36 00:01:19,820 --> 00:01:20,770 shoot_puck 37 00:01:21,050 --> 00:01:22,939 and we'll work towards making the function into 38 00:01:22,940 --> 00:01:24,869 a method. The shoot_puck 39 00:01:24,870 --> 00:01:27,340 function will take a HockeyPlayer instance, 40 00:01:27,590 --> 00:01:29,860 which is the player that will be shooting the puck. 41 00:01:31,040 --> 00:01:32,899 Eventually, this function could take in a lot of 42 00:01:32,900 --> 00:01:34,840 data about the current state of the game. 43 00:01:35,540 --> 00:01:37,609 For now, we'll start our modeling by taking 44 00:01:37,610 --> 00:01:39,439 into account the number of seconds left 45 00:01:39,440 --> 00:01:40,600 in the current period. 46 00:01:42,070 --> 00:01:44,179 The actual implementation of this function 47 00:01:44,180 --> 00:01:45,730 isn't important for the moment. 48 00:01:46,150 --> 00:01:48,630 Feel free to add an implementation of your choosing 49 00:01:48,760 --> 00:01:50,229 that looks at the player's stats, 50 00:01:50,230 --> 00:01:51,399 and the seconds left, 51 00:01:51,400 --> 00:01:53,229 and prints out whether the puck went in the goal 52 00:01:53,230 --> 00:01:55,149 or not, according to how you want your hockey 53 00:01:55,150 --> 00:01:56,410 simulator to work. 54 00:01:57,160 --> 00:01:59,079 We've decided that, in our very 55 00:01:59,080 --> 00:02:00,690 unrealistic simulation, 56 00:02:01,120 --> 00:02:03,150 all players always make their goals 57 00:02:03,230 --> 00:02:05,100 unless there's under 5 minutes left, 58 00:02:05,350 --> 00:02:07,189 in which case, only players at the center 59 00:02:07,190 --> 00:02:09,579 position have the composure to make shots, 60 00:02:09,580 --> 00:02:11,460 and players in other positions miss. 61 00:02:13,530 --> 00:02:14,939 This code works fine 62 00:02:14,940 --> 00:02:16,400 and prints Goal!. 63 00:02:18,470 --> 00:02:20,359 However, we're not communicating 64 00:02:20,360 --> 00:02:22,099 the capabilities of our program 65 00:02:22,100 --> 00:02:24,229 the best way we could. In 66 00:02:24,230 --> 00:02:25,990 our hockey simulation program, 67 00:02:26,330 --> 00:02:28,339 the shoot_puck function only makes 68 00:02:28,340 --> 00:02:30,229 sense in the context of a HockeyPlayer 69 00:02:30,230 --> 00:02:31,120 instance. 70 00:02:31,760 --> 00:02:33,899 Other types, like coach, fan, 71 00:02:33,900 --> 00:02:35,869 or mascot can't legally 72 00:02:35,870 --> 00:02:36,820 shoot the puck. 73 00:02:37,580 --> 00:02:39,709 We're defining behavior of the hockey player 74 00:02:39,710 --> 00:02:41,410 that every hockey player should have, 75 00:02:41,810 --> 00:02:43,429 and the code would be more organized 76 00:02:43,430 --> 00:02:45,259 if the behavior was clearly tied to the 77 00:02:45,260 --> 00:02:45,910 struct. 78 00:02:46,570 --> 00:02:47,950 That's where methods come in. 79 00:02:50,130 --> 00:02:51,360 How do we define a method? 80 00:02:51,790 --> 00:02:52,720 Let's find out. 81 00:02:54,010 --> 00:02:56,179 Methods are defined within a block 82 00:02:56,180 --> 00:02:58,120 that starts with the impl keyword, 83 00:02:58,310 --> 00:03:00,110 which is short for implementation. 84 00:03:01,280 --> 00:03:03,109 Then, we specify what we're implementing 85 00:03:03,110 --> 00:03:05,239 methods on, which, in this case, 86 00:03:05,240 --> 00:03:06,790 is the HockeyPlayer struct. 87 00:03:07,700 --> 00:03:09,559 Note that this code would look similar if 88 00:03:09,560 --> 00:03:11,749 we were implementing a method on an enum 89 00:03:11,750 --> 00:03:12,910 rather than a struct. 90 00:03:13,780 --> 00:03:15,639 We'd just put the name of the enum where 91 00:03:15,640 --> 00:03:17,460 we currently have the name of the struct. 92 00:03:18,100 --> 00:03:20,169 Next comes curly brackets to start the body 93 00:03:20,170 --> 00:03:22,149 of the block. Within 94 00:03:22,150 --> 00:03:24,179 the block, we use the fn keyword 95 00:03:24,180 --> 00:03:25,310 and the method name, 96 00:03:25,560 --> 00:03:26,920 just like with functions. 97 00:03:27,840 --> 00:03:29,369 A big difference between functions 98 00:03:29,370 --> 00:03:31,429 and methods is that the first parameter 99 00:03:31,430 --> 00:03:33,389 of a method is always a form 100 00:03:33,390 --> 00:03:35,249 of self, which refers 101 00:03:35,250 --> 00:03:37,320 to the type that we're defining the method on - 102 00:03:37,830 --> 00:03:39,920 in this case, a HockeyPlayer instance. 103 00:03:40,290 --> 00:03:42,440 The rest of the parameters of the method 104 00:03:42,510 --> 00:03:44,699 are the same as the rest of the parameters of the function 105 00:03:44,700 --> 00:03:45,410 we had. 106 00:03:45,900 --> 00:03:47,759 And whatever implementation you have would be the 107 00:03:47,760 --> 00:03:49,799 same as well, except wherever 108 00:03:49,800 --> 00:03:51,680 you used the HockeyPlayer parameter, 109 00:03:51,780 --> 00:03:52,619 you'd use self 110 00:03:52,620 --> 00:03:53,330 instead. 111 00:03:55,180 --> 00:03:57,099 Now that we have a method defined, what 112 00:03:57,100 --> 00:03:58,370 does it look like to call it? 113 00:04:00,340 --> 00:04:02,139 Instead of having the function name 114 00:04:02,140 --> 00:04:03,969 and passing the HockeyPlayer instance 115 00:04:03,970 --> 00:04:05,400 as the first argument, 116 00:04:06,010 --> 00:04:08,180 we can specify the HockeyPlayer instance, 117 00:04:08,280 --> 00:04:09,939 then a dot, then the name 118 00:04:09,940 --> 00:04:11,430 of the method we want to call, 119 00:04:11,680 --> 00:04:14,040 and the remaining arguments that aren't self. 120 00:04:15,980 --> 00:04:17,869 Now this code works just like the code 121 00:04:17,870 --> 00:04:19,900 where shoot_puck was a function, 122 00:04:20,500 --> 00:04:22,369 but we've more clearly communicated that 123 00:04:22,370 --> 00:04:24,259 shooting a puck is behavior that a hockey 124 00:04:24,260 --> 00:04:25,570 player instance has. 125 00:04:27,600 --> 00:04:29,639 Related to methods are associated 126 00:04:29,640 --> 00:04:31,599 functions. Let's take 127 00:04:31,600 --> 00:04:33,720 a look at associated functions for a minute 128 00:04:34,000 --> 00:04:35,079 and see how they compare 129 00:04:35,080 --> 00:04:36,219 with regular functions 130 00:04:36,220 --> 00:04:37,320 and with methods. 131 00:04:39,390 --> 00:04:41,399 Associated functions are defined 132 00:04:41,400 --> 00:04:43,679 within an impl block on a struct 133 00:04:43,680 --> 00:04:46,120 or an enum, the same as methods. 134 00:04:47,260 --> 00:04:49,590 There's still behavior that's related to the type, 135 00:04:50,080 --> 00:04:51,939 so we want to organize that behavior 136 00:04:51,940 --> 00:04:53,049 so that it's associated 137 00:04:53,050 --> 00:04:54,909 with the type. Unlike 138 00:04:54,910 --> 00:04:56,739 methods, they don't take self 139 00:04:56,740 --> 00:04:59,079 as a parameter. Associated 140 00:04:59,080 --> 00:05:01,119 functions are commonly used to create 141 00:05:01,120 --> 00:05:03,099 instances of type, so 142 00:05:03,100 --> 00:05:05,139 they don't have a self instance to operate 143 00:05:05,140 --> 00:05:05,640 on. 144 00:05:07,730 --> 00:05:09,769 For example, here's an associated 145 00:05:09,770 --> 00:05:11,440 function named new 146 00:05:11,740 --> 00:05:13,579 that creates an instance of a HockeyPlayer 147 00:05:13,580 --> 00:05:15,469 struct from the given name, 148 00:05:15,470 --> 00:05:16,930 number, and position. 149 00:05:18,140 --> 00:05:20,029 This function always starts the goals_ytd 150 00:05:20,030 --> 00:05:22,120 field at 0. 151 00:05:23,050 --> 00:05:24,999 Note that new isn't a special 152 00:05:25,000 --> 00:05:26,899 function name in Rust like it is 153 00:05:26,900 --> 00:05:28,280 in languages like Ruby, 154 00:05:28,830 --> 00:05:30,699 but by convention, many Rust types 155 00:05:30,700 --> 00:05:32,649 define an associated function named 156 00:05:32,650 --> 00:05:33,270 new 157 00:05:33,510 --> 00:05:35,730 that creates new instances of that type. 158 00:05:37,590 --> 00:05:39,510 To call an associated function, 159 00:05:39,780 --> 00:05:41,799 specify the type name, then two 160 00:05:41,800 --> 00:05:43,910 colons, then the function name. 161 00:05:44,670 --> 00:05:46,619 The associated function is namespaced 162 00:05:46,620 --> 00:05:47,930 beneath the type name. 163 00:05:48,450 --> 00:05:50,459 This code will function similarly to the code 164 00:05:50,460 --> 00:05:52,379 we had before in that we have 165 00:05:52,380 --> 00:05:54,140 a new HockeyPlayer instance. 166 00:05:54,780 --> 00:05:56,699 The difference is the goals_ytd 167 00:05:56,700 --> 00:05:58,520 will be 0 instead of 7. 168 00:06:00,620 --> 00:06:02,020 Returning to methods, 169 00:06:02,480 --> 00:06:04,519 let's talk about the different forms of self 170 00:06:04,520 --> 00:06:06,349 that a method can take, which 171 00:06:06,350 --> 00:06:08,269 has to do with whether the method only needs to 172 00:06:08,270 --> 00:06:09,160 read data 173 00:06:09,500 --> 00:06:11,410 or whether it needs to write data too. 174 00:06:13,630 --> 00:06:15,609 We actually glossed over a problem our code 175 00:06:15,610 --> 00:06:17,679 currently has: a player 176 00:06:17,680 --> 00:06:19,950 instance can only shoot the puck once. 177 00:06:20,730 --> 00:06:22,739 If we try to have the same player shoot the puck 178 00:06:22,740 --> 00:06:23,360 again, 179 00:06:23,760 --> 00:06:25,619 we get an error saying use 180 00:06:25,620 --> 00:06:27,110 of moved value: 'player'. 181 00:06:27,300 --> 00:06:29,129 This has to do with Rust's system 182 00:06:29,130 --> 00:06:30,140 of ownership 183 00:06:30,510 --> 00:06:32,790 and the next unit is all about ownership, 184 00:06:33,150 --> 00:06:35,129 so don't worry about understanding why this error 185 00:06:35,130 --> 00:06:36,530 happens right this second. 186 00:06:38,660 --> 00:06:40,529 A better way to define the shoot_puck 187 00:06:40,530 --> 00:06:42,160 method in this context 188 00:06:42,350 --> 00:06:44,179 is for it to borrow self instead 189 00:06:44,180 --> 00:06:46,069 of taking ownership, which we 190 00:06:46,070 --> 00:06:47,189 indicate with an &. 191 00:06:47,190 --> 00:06:49,149 Again, we're 192 00:06:49,150 --> 00:06:51,139 going to go into a lot more detail on this 193 00:06:51,140 --> 00:06:52,150 in the next unit. 194 00:06:52,790 --> 00:06:54,889 Making this change fixes the error 195 00:06:54,890 --> 00:06:56,719 and we can now call shoot_puck more 196 00:06:56,720 --> 00:06:57,520 than once. 197 00:06:59,520 --> 00:07:01,379 &self is for methods 198 00:07:01,380 --> 00:07:03,369 that don't change anything about self's 199 00:07:03,370 --> 00:07:05,219 values. In this 200 00:07:05,220 --> 00:07:07,319 implementation, we're only reading 201 00:07:07,320 --> 00:07:09,179 from the position field of the HockeyPlayer 202 00:07:09,180 --> 00:07:11,330 instance, not changing anything. 203 00:07:13,190 --> 00:07:15,490 Let's say we did want to change self 204 00:07:15,710 --> 00:07:17,599 to increase the count of the goals_ytd 205 00:07:17,600 --> 00:07:19,699 when shooting the puck 206 00:07:19,700 --> 00:07:21,110 and the player gets a goal. 207 00:07:23,920 --> 00:07:24,909 If we make this change 208 00:07:24,910 --> 00:07:26,460 and try to compile the code, 209 00:07:26,860 --> 00:07:28,749 we get an error that we cannot assign to the 210 00:07:28,750 --> 00:07:30,300 field, goals_ytd. 211 00:07:32,320 --> 00:07:34,389 Just like we have to explicitly annotate 212 00:07:34,390 --> 00:07:36,090 variables that can be mutated, 213 00:07:36,610 --> 00:07:38,549 we have to annotate methods that can mutate 214 00:07:38,550 --> 00:07:38,950 self. 215 00:07:40,030 --> 00:07:41,949 We do this by making the first parameter of 216 00:07:41,950 --> 00:07:44,120 the method &mut self. 217 00:07:46,100 --> 00:07:47,359 This fixes the error, 218 00:07:47,360 --> 00:07:49,369 and we can see that the method has modified 219 00:07:49,370 --> 00:07:50,470 the player instance. 220 00:07:52,190 --> 00:07:53,290 In this module, 221 00:07:53,360 --> 00:07:54,589 we covered how methods 222 00:07:54,590 --> 00:07:56,870 let us add behavior to data types, 223 00:07:57,230 --> 00:07:59,290 how to define and call methods, 224 00:07:59,730 --> 00:08:01,669 associated functions to find in impl 225 00:08:01,670 --> 00:08:02,869 blocks that are associated 226 00:08:02,870 --> 00:08:03,710 with a type 227 00:08:03,740 --> 00:08:05,630 but not with an instance of the type, 228 00:08:06,350 --> 00:08:08,269 and the various forms of self that 229 00:08:08,270 --> 00:08:10,399 methods take depending on whether they read 230 00:08:10,400 --> 00:08:11,470 or write data. 231 00:08:12,770 --> 00:08:14,410 Those are the basics of methods 232 00:08:14,770 --> 00:08:16,659 and the end of the syntax introduction for this 233 00:08:16,660 --> 00:08:17,380 course. 234 00:08:18,520 --> 00:08:19,380 Next unit, 235 00:08:19,600 --> 00:08:21,789 we'll find out all about the concepts of ownership 236 00:08:21,790 --> 00:08:22,660 and borrowing. 237 00:08:23,320 --> 00:08:25,870 We'll get comfortable with when we should be adding ampersands.