1 00:00:06,282 --> 00:00:09,240 - In this section we are going to dig a bit deeper 2 00:00:09,240 --> 00:00:12,030 into some trait techniques with Rust. 3 00:00:12,030 --> 00:00:14,310 In particular for a trait, 4 00:00:14,310 --> 00:00:17,580 we'll see how a trait can define default methods. 5 00:00:17,580 --> 00:00:21,660 Methods that are already implemented that can be overridden 6 00:00:21,660 --> 00:00:24,330 but don't have to be overridden. 7 00:00:24,330 --> 00:00:27,780 We'll also see how a trait can define associated constants. 8 00:00:27,780 --> 00:00:30,866 You can define constants in a trait. 9 00:00:30,866 --> 00:00:32,700 You can even override those constants 10 00:00:32,700 --> 00:00:34,740 with different values in a structure. 11 00:00:34,740 --> 00:00:36,420 We'll see that as well 12 00:00:36,420 --> 00:00:40,364 and we'll see how a structure can implement multiple traits. 13 00:00:40,364 --> 00:00:42,930 A structure can implement multiple traits. 14 00:00:42,930 --> 00:00:44,550 It's like multiple inheritance 15 00:00:44,550 --> 00:00:48,600 of interfaces in other languages, right? 16 00:00:48,600 --> 00:00:52,230 Okay, so first of all, a trait can define default methods. 17 00:00:52,230 --> 00:00:55,560 In other words, a method that has a default implementation. 18 00:00:55,560 --> 00:00:57,830 And this means that they can be overridden 19 00:00:57,830 --> 00:01:01,380 in a structure if desired, but they don't have to be. 20 00:01:01,380 --> 00:01:02,550 So here's an example. 21 00:01:02,550 --> 00:01:05,130 You just basically give a body to a method. 22 00:01:05,130 --> 00:01:06,180 Here's a trait. 23 00:01:06,180 --> 00:01:08,100 I've got a trait called Log. 24 00:01:08,100 --> 00:01:10,140 It has an abstract method. 25 00:01:10,140 --> 00:01:12,630 Remember, everything's public by the way. 26 00:01:12,630 --> 00:01:15,800 It has an abstract method, which must be overridden 27 00:01:15,800 --> 00:01:18,990 in a structure, and then it has another method 28 00:01:18,990 --> 00:01:22,650 log_verbose that has a default implementation. 29 00:01:22,650 --> 00:01:25,620 So you can override it in a structure 30 00:01:25,620 --> 00:01:26,610 but you don't have to. 31 00:01:26,610 --> 00:01:29,190 It'll fall back on this implementation. 32 00:01:29,190 --> 00:01:30,870 And the log_verbose method 33 00:01:30,870 --> 00:01:34,800 by default will print the current timestamp 34 00:01:34,800 --> 00:01:36,450 and then notice what it does here. 35 00:01:36,450 --> 00:01:37,833 It calls self.log. 36 00:01:38,730 --> 00:01:39,900 It'll call the log method 37 00:01:39,900 --> 00:01:42,150 that you will have implemented in your structure. 38 00:01:42,150 --> 00:01:45,660 So some structure will have implemented this log trait 39 00:01:45,660 --> 00:01:49,050 and that structure will defined a log method. 40 00:01:49,050 --> 00:01:50,970 And this is calling the log method. 41 00:01:50,970 --> 00:01:52,650 It's kind of self messaging. 42 00:01:52,650 --> 00:01:54,480 It's effectively calling the log method 43 00:01:54,480 --> 00:01:59,070 which you will have overridden in your subclass effectively. 44 00:01:59,070 --> 00:02:03,030 So a method that you must implement log 45 00:02:03,030 --> 00:02:06,000 and a method that you can implement or you can just rely 46 00:02:06,000 --> 00:02:08,553 in this default implementation if you like. 47 00:02:09,810 --> 00:02:10,830 Okay, next. 48 00:02:10,830 --> 00:02:15,690 Then a trait can also define associated constants, 49 00:02:15,690 --> 00:02:18,930 constant associated with the interface, okay? 50 00:02:18,930 --> 00:02:21,840 You can override them in structures if you want to 51 00:02:21,840 --> 00:02:23,820 but you don't have to if you don't want to. 52 00:02:23,820 --> 00:02:25,050 So here's an example. 53 00:02:25,050 --> 00:02:28,680 It's just like a magic number associated with that trait. 54 00:02:28,680 --> 00:02:32,670 So I've got a trait called log and it defines a constant 55 00:02:32,670 --> 00:02:36,240 and associated constant associated with this trait. 56 00:02:36,240 --> 00:02:38,910 Log timestamp, it's a Boolean. 57 00:02:38,910 --> 00:02:42,000 It's gonna basically tell the trait whether or not 58 00:02:42,000 --> 00:02:45,600 to display the timestamp when it's writing log messages. 59 00:02:45,600 --> 00:02:48,390 So initially I've set the log timestamp flag 60 00:02:48,390 --> 00:02:52,020 to be false like so, right? 61 00:02:52,020 --> 00:02:57,020 So to access an associate constant, like display timestamp 62 00:02:57,030 --> 00:02:59,550 in a trait method, you'd use this syntax. 63 00:02:59,550 --> 00:03:03,600 Self::Constant_Name, self is kind of 64 00:03:03,600 --> 00:03:06,900 like a type alias for the structure 65 00:03:06,900 --> 00:03:09,600 in which you are operating in currently, okay? 66 00:03:09,600 --> 00:03:12,003 It's like an alias for the current structure. 67 00:03:12,990 --> 00:03:14,520 So here's an example. 68 00:03:14,520 --> 00:03:19,520 My log trait defines an associated constant log timestamp 69 00:03:20,040 --> 00:03:24,120 sets it to false initially, my log_verbose method 70 00:03:24,120 --> 00:03:28,200 which will output the current object in a verbose format. 71 00:03:28,200 --> 00:03:32,220 First of all, it looks at the log timestamp field 72 00:03:32,220 --> 00:03:33,600 to see if it's true or false. 73 00:03:33,600 --> 00:03:36,750 If it's true, then it prints the timestamp. 74 00:03:36,750 --> 00:03:37,890 And in any case, 75 00:03:37,890 --> 00:03:41,970 it calls the log method to output the regular log function. 76 00:03:41,970 --> 00:03:44,460 So Self is an alias 77 00:03:44,460 --> 00:03:47,730 for the type which will have implemented the structure. 78 00:03:47,730 --> 00:03:52,050 You don't say log here, you don't use your trait type. 79 00:03:52,050 --> 00:03:53,910 What you use is Self is like an alias 80 00:03:53,910 --> 00:03:57,150 for whichever structure has implemented this trait 81 00:03:57,150 --> 00:04:01,530 that's the name of the structure that will be replaced here. 82 00:04:01,530 --> 00:04:06,530 Okay, a structure can implement multiple traits. 83 00:04:06,570 --> 00:04:08,790 You define a separate implementation block 84 00:04:08,790 --> 00:04:11,550 for each trait that you want to implement. 85 00:04:11,550 --> 00:04:13,920 Quite straightforward, and we've kind of seen something 86 00:04:13,920 --> 00:04:16,500 like this already in the previous example. 87 00:04:16,500 --> 00:04:20,700 Here's my structure, employee with data. 88 00:04:20,700 --> 00:04:23,430 Here's the regular implementation of employee, you know 89 00:04:23,430 --> 00:04:27,930 the regular methods like new, and here's the implementation 90 00:04:27,930 --> 00:04:30,750 of the print trait for employee. 91 00:04:30,750 --> 00:04:33,810 So whatever methods the print trait requires 92 00:04:33,810 --> 00:04:36,060 will be implemented in this block. 93 00:04:36,060 --> 00:04:37,680 And here's the implementation block 94 00:04:37,680 --> 00:04:39,900 for the log trait for employee. 95 00:04:39,900 --> 00:04:43,710 So I actually quite like this, invest in a normal, 96 00:04:43,710 --> 00:04:47,430 in a other object oriented language like Java and so on. 97 00:04:47,430 --> 00:04:50,760 You would have one class that defies all the methods, 98 00:04:50,760 --> 00:04:52,740 the methods that implement one interface 99 00:04:52,740 --> 00:04:54,480 plus the methods for another interface 100 00:04:54,480 --> 00:04:58,200 all kind of mixed up in the same class definition. 101 00:04:58,200 --> 00:05:01,500 And in Rust, you have a separate block per slice. 102 00:05:01,500 --> 00:05:04,920 So here's the kind of basic implementation for employee. 103 00:05:04,920 --> 00:05:06,090 Here's the implementation 104 00:05:06,090 --> 00:05:09,300 of the print interface trait for employee. 105 00:05:09,300 --> 00:05:10,380 And here's the implementation 106 00:05:10,380 --> 00:05:11,970 of the log trait for employee. 107 00:05:11,970 --> 00:05:15,393 So actually nicely partitioned into sections. 108 00:05:16,320 --> 00:05:17,850 So we need to see an example. 109 00:05:17,850 --> 00:05:20,880 We'll go into the lesson 12 traits project. 110 00:05:20,880 --> 00:05:22,290 The files we're going to look at in here 111 00:05:22,290 --> 00:05:25,170 obviously we'll start with main.rs. 112 00:05:25,170 --> 00:05:29,130 Then we'll have a look at the trait defined in log.rs, 113 00:05:29,130 --> 00:05:33,810 and we have the structure implements defined in employee.rs, 114 00:05:33,810 --> 00:05:35,730 and then we'll see how they use that code 115 00:05:35,730 --> 00:05:39,780 and the actual demo function, demo_trait_techniques, okay? 116 00:05:39,780 --> 00:05:41,400 And then obviously we'll run the project 117 00:05:41,400 --> 00:05:42,750 once we've dissected the code. 118 00:05:42,750 --> 00:05:44,580 So let's have a look. 119 00:05:44,580 --> 00:05:49,580 Okay, so from the top then main.rs 120 00:05:49,590 --> 00:05:51,413 we're going to run demo_trait_techniques. 121 00:05:52,920 --> 00:05:57,920 And we're gonna look at the trait will be in log rs here. 122 00:05:58,800 --> 00:06:03,450 And so it's public, so we can access the treat elsewhere. 123 00:06:03,450 --> 00:06:07,650 Remember, every member in a treat is implicitly public. 124 00:06:07,650 --> 00:06:08,760 You can't say public. 125 00:06:08,760 --> 00:06:13,760 It is, it has an associated constant log timestamp, false. 126 00:06:15,480 --> 00:06:16,650 I can override that 127 00:06:16,650 --> 00:06:20,460 if I want to in a structure, bear that in mind. 128 00:06:20,460 --> 00:06:22,050 I've got an abstract method. 129 00:06:22,050 --> 00:06:23,850 A structure must implement that. 130 00:06:23,850 --> 00:06:25,083 So the employee structure 131 00:06:25,083 --> 00:06:27,723 will have to implement the log method. 132 00:06:28,710 --> 00:06:30,690 I've got a log_verbose method 133 00:06:30,690 --> 00:06:33,750 which is kind of like an adapter on top of the log method. 134 00:06:33,750 --> 00:06:35,010 You often see this. 135 00:06:35,010 --> 00:06:38,130 There'll be a method that must be overridden 136 00:06:38,130 --> 00:06:41,820 and some kind of wrapper method, which will underneath 137 00:06:41,820 --> 00:06:44,010 will actually call log eventually, 138 00:06:44,010 --> 00:06:46,080 but it provides some kind of wrapper functionality 139 00:06:46,080 --> 00:06:47,850 as well around it. 140 00:06:47,850 --> 00:06:51,240 And that wrapper functionality has a default implementation. 141 00:06:51,240 --> 00:06:52,620 It's like a standard wrapper. 142 00:06:52,620 --> 00:06:55,290 So if you call the log_verbose method 143 00:06:55,290 --> 00:07:00,290 then by default it'll print like a banner at the top 144 00:07:00,540 --> 00:07:02,340 and a banner at the bottom, 145 00:07:02,340 --> 00:07:07,340 depending on the value of log timestamp, which is false here 146 00:07:07,440 --> 00:07:10,290 but could be overridden in the subclass. 147 00:07:10,290 --> 00:07:13,350 So basically whatever structure we are looking at 148 00:07:13,350 --> 00:07:15,720 have a look at the log timestamp flag. 149 00:07:15,720 --> 00:07:19,323 And if it's true, then also I'll put the timestamp, 150 00:07:20,430 --> 00:07:23,130 also called the original log method, okay? 151 00:07:23,130 --> 00:07:25,470 So whatever the original log method would've been done 152 00:07:25,470 --> 00:07:30,150 that's still gonna be called, but with this beautiful banner 153 00:07:30,150 --> 00:07:31,293 that sits around it. 154 00:07:32,310 --> 00:07:34,920 So that's my log trait. 155 00:07:34,920 --> 00:07:38,913 A constant that I can override in my subclass if I want to. 156 00:07:39,807 --> 00:07:42,360 A method that I must implement 157 00:07:42,360 --> 00:07:46,170 and a method that I can't implement, but typically won't. 158 00:07:46,170 --> 00:07:47,640 That's the general idea. 159 00:07:47,640 --> 00:07:50,490 When a trait has a default method implementation 160 00:07:50,490 --> 00:07:53,400 it means you are unlikely to need to implement 161 00:07:53,400 --> 00:07:54,390 this method yourself. 162 00:07:54,390 --> 00:07:55,890 Here's the default implementation 163 00:07:55,890 --> 00:07:57,390 that I've already thought of. 164 00:07:57,390 --> 00:07:59,250 You're probably just gonna use this, 165 00:07:59,250 --> 00:08:01,620 you can override it if you want to. 166 00:08:01,620 --> 00:08:04,830 Most of the time you're probably not going to need to. 167 00:08:04,830 --> 00:08:09,330 Right, so the structure which implements log is employee 168 00:08:09,330 --> 00:08:11,070 and that's all of my structures 169 00:08:11,070 --> 00:08:13,560 remember are in my structs. 170 00:08:13,560 --> 00:08:17,400 So employee.rs, let's have a look. 171 00:08:17,400 --> 00:08:21,510 So the data for employee is same as before. 172 00:08:21,510 --> 00:08:24,660 An employee has a name and a salary and a full-time status. 173 00:08:24,660 --> 00:08:27,030 The regular implementation for employee, 174 00:08:27,030 --> 00:08:29,040 you can give the employee a pay rise 175 00:08:29,040 --> 00:08:31,140 and you can create a new instance 176 00:08:31,140 --> 00:08:33,153 using the associated function new. 177 00:08:34,380 --> 00:08:38,460 Then we have the implementation of the print trait. 178 00:08:38,460 --> 00:08:39,753 We saw that earlier. 179 00:08:40,680 --> 00:08:44,100 It just implemented the print method to print out 180 00:08:44,100 --> 00:08:46,860 the employee's details and also, 181 00:08:46,860 --> 00:08:50,403 and separately the implementation of the log trait. 182 00:08:51,360 --> 00:08:56,190 I've chosen to override the log timestamp constant, okay? 183 00:08:56,190 --> 00:08:58,730 Because remember in my trait for log, 184 00:09:05,820 --> 00:09:09,990 the log timestamp was initially false, okay. 185 00:09:09,990 --> 00:09:11,370 I could've just left it like that. 186 00:09:11,370 --> 00:09:12,723 I would've inherited that. 187 00:09:13,710 --> 00:09:17,010 I've actually overridden it in my subclass. 188 00:09:17,010 --> 00:09:18,780 In my structure if you like, 189 00:09:18,780 --> 00:09:21,963 I've overridden log timestamp to make it true. 190 00:09:23,910 --> 00:09:27,870 Okay, so you can redefine it in the subclass, 191 00:09:27,870 --> 00:09:29,883 in the structure as being true. 192 00:09:30,960 --> 00:09:33,960 In the interface or the trait, 193 00:09:33,960 --> 00:09:36,693 it said I had to implement the log method. 194 00:09:37,530 --> 00:09:38,580 So I have, 195 00:09:38,580 --> 00:09:40,920 because obviously only the employee structure 196 00:09:40,920 --> 00:09:44,010 knows what it means to log the data for an employee. 197 00:09:44,010 --> 00:09:45,870 So that must be overridden. 198 00:09:45,870 --> 00:09:49,380 And it is, here it is. 199 00:09:49,380 --> 00:09:51,900 So here's the implementation of the log method. 200 00:09:51,900 --> 00:09:54,570 It logs the employee's name, salary, and fault, 201 00:09:54,570 --> 00:09:56,190 it just outputs them to the screen. 202 00:09:56,190 --> 00:10:00,690 I haven't chosen to implement the log_verbose method 203 00:10:00,690 --> 00:10:03,570 so I just inherit the default implementation 204 00:10:03,570 --> 00:10:07,350 from the trait and usually that's sufficient. 205 00:10:07,350 --> 00:10:10,950 Okay, so my employee structure will inherit that function 206 00:10:10,950 --> 00:10:11,793 for free. 207 00:10:13,050 --> 00:10:14,610 So let's just see how to input, 208 00:10:14,610 --> 00:10:17,460 how to actually make use of my employee. 209 00:10:17,460 --> 00:10:19,380 So that's my employee structure 210 00:10:19,380 --> 00:10:22,710 with the interfaces that it implements 211 00:10:22,710 --> 00:10:24,570 and the data that it has. 212 00:10:24,570 --> 00:10:27,870 Let's see how to use it in my code here. 213 00:10:27,870 --> 00:10:29,243 Demo_trait_techniques, okay? 214 00:10:31,410 --> 00:10:36,060 So create a new employee Mary, give Mary a pay rise. 215 00:10:36,060 --> 00:10:39,930 Invoke functionality defined in the log trait, 216 00:10:39,930 --> 00:10:43,950 invoke the log method and invoke log_verbose 217 00:10:43,950 --> 00:10:46,170 with the heading and with the timestamp. 218 00:10:46,170 --> 00:10:51,170 Oh, and by the way, you can access the employee timestamp 219 00:10:52,170 --> 00:10:57,170 because if I go back to square one in my log trait 220 00:10:58,560 --> 00:11:01,770 remember that whenever you define anything in a trait 221 00:11:01,770 --> 00:11:04,080 it is implicitly public, okay? 222 00:11:04,080 --> 00:11:06,390 So this here is public 223 00:11:06,390 --> 00:11:09,210 and I can access that in my external code. 224 00:11:09,210 --> 00:11:13,650 And I have, okay, so I said, by the way 225 00:11:13,650 --> 00:11:16,410 the value of the employee log timestamp is 226 00:11:16,410 --> 00:11:19,230 and that'll output the value of log timestamp. 227 00:11:19,230 --> 00:11:22,380 And as you remember in the employee structure, 228 00:11:22,380 --> 00:11:24,263 I set that to be true, okay? 229 00:11:25,192 --> 00:11:28,897 So in my implementation of the log trait 230 00:11:29,760 --> 00:11:31,293 I redefined that to be true. 231 00:11:32,280 --> 00:11:33,750 I just mentioned one more time. 232 00:11:33,750 --> 00:11:36,630 When you implement a trait in a structure 233 00:11:36,630 --> 00:11:40,080 all of these fields here in members are also public, 234 00:11:40,080 --> 00:11:42,150 traits are all about public interface. 235 00:11:42,150 --> 00:11:43,780 So you don't say pub 236 00:11:44,730 --> 00:11:47,220 and you don't say pub here they are implicitly public 237 00:11:47,220 --> 00:11:51,150 and can therefore be accessed in your client code, right? 238 00:11:51,150 --> 00:11:54,000 So with a relatively high degree of confidence 239 00:11:54,000 --> 00:11:59,000 we should run this code and hope cargo run. 240 00:12:02,870 --> 00:12:06,030 Okay, so in demo_trait_techniques 241 00:12:06,030 --> 00:12:08,760 remember I called the log method, first of all 242 00:12:08,760 --> 00:12:12,090 which just output Mary's incremented salary 243 00:12:12,090 --> 00:12:13,710 and her full-time status. 244 00:12:13,710 --> 00:12:16,800 And then I called log_verbose and log_verbose printed 245 00:12:16,800 --> 00:12:18,630 the banner. 246 00:12:18,630 --> 00:12:22,650 I printed the timestamp because the Boolean flag was true. 247 00:12:22,650 --> 00:12:24,390 And then they called the log method 248 00:12:24,390 --> 00:12:27,930 and then it printed the end banner like so. 249 00:12:27,930 --> 00:12:30,840 Great, so final recap then. 250 00:12:30,840 --> 00:12:33,900 In a trait, you can define constants 251 00:12:33,900 --> 00:12:35,580 which can be overridden. 252 00:12:35,580 --> 00:12:38,910 You can define methods that must be overridden 253 00:12:38,910 --> 00:12:41,530 and default methods that can be overridden 254 00:12:42,690 --> 00:12:45,270 but don't need to be and typically aren't. 255 00:12:45,270 --> 00:12:48,210 And you can also, obviously in a structure, 256 00:12:48,210 --> 00:12:51,210 you can implement as many interfaces as you like or traits. 257 00:12:51,210 --> 00:12:55,350 And each trait implementation is clearly delineated 258 00:12:55,350 --> 00:12:58,350 easy for you to say, easily delineated 259 00:12:58,350 --> 00:13:00,420 as a separate block like so. 260 00:13:00,420 --> 00:13:01,970 So it's quite elegant, I think.