1 00:00:06,797 --> 00:00:08,070 - In the previous section, 2 00:00:08,070 --> 00:00:11,580 we saw how to define associated functions for a structure. 3 00:00:11,580 --> 00:00:14,490 So here's a quick recap before we move on. 4 00:00:14,490 --> 00:00:18,090 I've defined a public structure Point3D, 5 00:00:18,090 --> 00:00:20,340 I've defined the implementation block. 6 00:00:20,340 --> 00:00:24,450 It has a public function, I've called it new by choice. 7 00:00:24,450 --> 00:00:26,250 It doesn't have a self parameter, 8 00:00:26,250 --> 00:00:28,980 therefore it's an associated function, 9 00:00:28,980 --> 00:00:31,710 effectively a static function in other languages. 10 00:00:31,710 --> 00:00:34,740 You invoke this method on the name of the structure 11 00:00:34,740 --> 00:00:37,860 you'd say Point3D, colon, colon, new 12 00:00:37,860 --> 00:00:39,450 and it would create presumably, 13 00:00:39,450 --> 00:00:42,603 and return a Point3D object initialized 14 00:00:42,603 --> 00:00:45,543 with the X, Y, and Z parameters that you pass in. 15 00:00:46,470 --> 00:00:48,510 So associated functions pertain 16 00:00:48,510 --> 00:00:51,480 to the entire structure type, not to an instance. 17 00:00:51,480 --> 00:00:53,757 You invoke them on the structure type, 18 00:00:53,757 --> 00:00:56,790 typically like here as a factory function 19 00:00:56,790 --> 00:00:59,850 to create a new instance and to return it. 20 00:00:59,850 --> 00:01:02,301 You can also define associated data, 21 00:01:02,301 --> 00:01:06,210 associated data pertains to the entire structure, 22 00:01:06,210 --> 00:01:08,370 not to any particular instance. 23 00:01:08,370 --> 00:01:11,790 So it's effectively shared by all instances, 24 00:01:11,790 --> 00:01:14,040 similar to the idea of static data 25 00:01:14,040 --> 00:01:16,099 in other object-oriented languages 26 00:01:16,099 --> 00:01:19,080 Right, well, you don't there are two ways 27 00:01:19,080 --> 00:01:22,080 to define associated data as it's called, 28 00:01:22,080 --> 00:01:25,578 you can either define associated data which is constant 29 00:01:25,578 --> 00:01:30,030 and doesn't change and no net compile time, 30 00:01:30,030 --> 00:01:31,170 that's the key point. 31 00:01:31,170 --> 00:01:33,750 Or you can define associated data, 32 00:01:33,750 --> 00:01:37,080 which isn't constant, which could change. 33 00:01:37,080 --> 00:01:38,940 Okay, so two different techniques. 34 00:01:38,940 --> 00:01:42,960 If you want to have per structure data that is fixed, 35 00:01:42,960 --> 00:01:44,640 then you can declare it as constant. 36 00:01:44,640 --> 00:01:47,340 If you have per data structure that can change, 37 00:01:47,340 --> 00:01:49,350 then you need to find it as static. 38 00:01:49,350 --> 00:01:50,183 All right, so we can look 39 00:01:50,183 --> 00:01:53,790 at these two different techniques in the next few minutes. 40 00:01:53,790 --> 00:01:55,890 So the easiest approach is 41 00:01:55,890 --> 00:01:58,320 when you have constant associated data, 42 00:01:58,320 --> 00:02:02,640 data that's fixed and is kind of shared by all instances, 43 00:02:02,640 --> 00:02:05,490 like static constant in other languages. 44 00:02:05,490 --> 00:02:08,610 So what you do is you define a constant field 45 00:02:08,610 --> 00:02:10,980 inside the implementation block. 46 00:02:10,980 --> 00:02:14,590 You optionally make it public and then you can access it 47 00:02:16,350 --> 00:02:19,710 anywhere in your methods. 48 00:02:19,710 --> 00:02:22,704 Okay, so let's have a look here. 49 00:02:22,704 --> 00:02:26,220 I've got a type called Employee. 50 00:02:26,220 --> 00:02:30,690 I've defined it in the file mytypes/employee.rs. 51 00:02:30,690 --> 00:02:33,690 So the structure template, if you like, 52 00:02:33,690 --> 00:02:35,250 will define the data, 53 00:02:35,250 --> 00:02:38,490 and then in the implementation block for employee 54 00:02:38,490 --> 00:02:43,050 as well as having functions, I can define a constant field. 55 00:02:43,050 --> 00:02:45,750 The maximum salary that any employee is allowed 56 00:02:45,750 --> 00:02:48,390 to earn is fixed for all employees, 57 00:02:48,390 --> 00:02:52,230 it's the same maximum salary anyone can earn and it's fixed. 58 00:02:52,230 --> 00:02:54,060 So I've made a constant. 59 00:02:54,060 --> 00:02:56,010 Remember when you declare constant, 60 00:02:56,010 --> 00:02:58,920 you have to specify the type explicitly. 61 00:02:58,920 --> 00:03:01,470 So it's an unsigned 64 bit. 62 00:03:01,470 --> 00:03:02,940 Turns out that the maximum salary 63 00:03:02,940 --> 00:03:07,445 that anyone can earn is 99,000 units. 64 00:03:07,445 --> 00:03:11,790 Right, so if you define a constant in your structure, 65 00:03:11,790 --> 00:03:15,660 then you can use it via its structuring. 66 00:03:15,660 --> 00:03:18,630 So here's a payrise method. 67 00:03:18,630 --> 00:03:20,880 You would take an employee, like employee1, 68 00:03:20,880 --> 00:03:24,660 employee1.payrise, you'd pass in the amount 69 00:03:24,660 --> 00:03:28,050 that you're hoping to give this employee as a pay rise. 70 00:03:28,050 --> 00:03:31,290 It adds the amount onto that person's salary. 71 00:03:31,290 --> 00:03:35,190 And then it checks to see whether we've overflowed, 72 00:03:35,190 --> 00:03:37,530 if the person's salary is no greater 73 00:03:37,530 --> 00:03:42,210 than the maximum salary defined at the structural level. 74 00:03:42,210 --> 00:03:46,740 So you can use self to access per instance data 75 00:03:46,740 --> 00:03:49,290 and then you use the class name or the structure name 76 00:03:49,290 --> 00:03:52,440 to access data that's defined 77 00:03:52,440 --> 00:03:55,470 at the entire structural level here. 78 00:03:55,470 --> 00:03:59,061 Okay, so it'll access the maximum salary, 79 00:03:59,061 --> 00:04:02,340 which is defined at the structural level. 80 00:04:02,340 --> 00:04:05,010 It's the same maximum salary for everybody. 81 00:04:05,010 --> 00:04:07,140 And it's a constant here, 82 00:04:07,140 --> 00:04:09,690 so if the person's salary has now exceeded 83 00:04:09,690 --> 00:04:12,990 the maximum salary, we just reset it to the maximum. 84 00:04:12,990 --> 00:04:16,530 So you can't earn more than 99,000 in my example. 85 00:04:16,530 --> 00:04:20,850 So this is how you can define shared data that's constant 86 00:04:20,850 --> 00:04:23,100 inside the implementation block. 87 00:04:23,100 --> 00:04:25,230 You define the constant field like that 88 00:04:25,230 --> 00:04:27,660 and then you use the name of the structure type 89 00:04:27,660 --> 00:04:29,910 in order to access it here. 90 00:04:29,910 --> 00:04:33,060 Okay, so that's when you have constant data. 91 00:04:33,060 --> 00:04:34,800 If you have non-constant data, 92 00:04:34,800 --> 00:04:36,960 it's quite a different approach. 93 00:04:36,960 --> 00:04:41,960 What you do is you define a static variable in the module, 94 00:04:42,240 --> 00:04:44,490 not actually inside the implementation block, 95 00:04:44,490 --> 00:04:46,800 but outside it's still in the same file, 96 00:04:46,800 --> 00:04:48,870 but outside the implementation block, 97 00:04:48,870 --> 00:04:51,150 you define a static variable, 98 00:04:51,150 --> 00:04:54,330 and then use it in your functions. 99 00:04:54,330 --> 00:04:56,098 Okay, so here's an example. 100 00:04:56,098 --> 00:05:00,690 I've got a static defined in the module, 101 00:05:00,690 --> 00:05:03,720 but outside the implementation block, okay? 102 00:05:03,720 --> 00:05:05,220 So this static, 103 00:05:05,220 --> 00:05:08,310 you don't define it inside the implementation block. 104 00:05:08,310 --> 00:05:11,419 You define it outside, it's still part of the module, 105 00:05:11,419 --> 00:05:15,040 but it's not actually inside the implementation block. 106 00:05:15,040 --> 00:05:18,570 So what I've got here is kind of like a, you know, 107 00:05:18,570 --> 00:05:20,970 when you insert data into a database, 108 00:05:20,970 --> 00:05:23,400 the database has an auto increment mechanism. 109 00:05:23,400 --> 00:05:25,170 Every time you create a new row, 110 00:05:25,170 --> 00:05:27,510 it automatically increments the ID. 111 00:05:27,510 --> 00:05:29,670 I've got some kind of similar mechanism here. 112 00:05:29,670 --> 00:05:33,610 NEXT_ID is kind of like a semi global counter 113 00:05:34,490 --> 00:05:37,560 called NEXT_ID, remember, you've gotta use capital letters 114 00:05:37,560 --> 00:05:40,019 for statics and you've gotta specify the type. 115 00:05:40,019 --> 00:05:41,850 You've gotta be really careful as well 116 00:05:41,850 --> 00:05:44,730 when you have statics that can change about thread safety, 117 00:05:44,730 --> 00:05:46,350 we talked about this earlier. 118 00:05:46,350 --> 00:05:49,320 You've gotta either use some kind of mutex 119 00:05:49,320 --> 00:05:51,810 or some kind of lazy initialization. 120 00:05:51,810 --> 00:05:55,560 You've gotta be careful when you have multiple statics. 121 00:05:55,560 --> 00:05:59,490 So I've used an atomic data type here, AtomicI32, 122 00:05:59,490 --> 00:06:03,000 an integer type that can be modified 123 00:06:03,000 --> 00:06:05,160 in a thread safe manner. 124 00:06:05,160 --> 00:06:08,610 So we we're not gonna get into thread safety issues. 125 00:06:08,610 --> 00:06:12,180 So this is a thread safe 32 bit integer, 126 00:06:12,180 --> 00:06:14,853 which I initialize to 0. 127 00:06:15,720 --> 00:06:18,990 And then every time I create a new employee, 128 00:06:18,990 --> 00:06:20,460 it'll create a new employee 129 00:06:20,460 --> 00:06:23,100 and it'll give that employee a different ID. 130 00:06:23,100 --> 00:06:26,760 The ID for each employee will be, well have a look here, 131 00:06:26,760 --> 00:06:30,330 it's gonna get the next ID, this atomic integer. 132 00:06:30,330 --> 00:06:34,050 It'll fetch the value, it'll add one to it, okay, 133 00:06:34,050 --> 00:06:35,910 it's basically increment the value 134 00:06:35,910 --> 00:06:40,080 and that incremented value will be the ID for this employee. 135 00:06:40,080 --> 00:06:42,750 So if I call the new function five times, 136 00:06:42,750 --> 00:06:44,220 every time I call new, 137 00:06:44,220 --> 00:06:49,220 it'll basically increment the global NEXT_ID. 138 00:06:49,530 --> 00:06:51,720 So each instance will have a different ID, 139 00:06:51,720 --> 00:06:55,410 ID 1, ID 2, ID 3, ID 4. 140 00:06:55,410 --> 00:06:57,330 It's like a self increment mechanism 141 00:06:57,330 --> 00:06:59,853 that you get in a relational database. 142 00:07:00,900 --> 00:07:05,610 Right, so that's how you implement shared data 143 00:07:05,610 --> 00:07:07,950 or associated data that can vary, 144 00:07:07,950 --> 00:07:11,820 define a static field outside the structure 145 00:07:11,820 --> 00:07:15,750 and then you can use it here, okay, so here, 146 00:07:15,750 --> 00:07:19,740 notice that we didn't specify the structure type 147 00:07:19,740 --> 00:07:24,480 as a prefix because NEXT_ID is defined in the module 148 00:07:24,480 --> 00:07:28,140 but it's not actually defined inside the scope of employee, 149 00:07:28,140 --> 00:07:30,060 it's defined at the file level, if you like, 150 00:07:30,060 --> 00:07:33,600 so we access it as a file level property. 151 00:07:33,600 --> 00:07:36,240 We don't specify the class name 152 00:07:36,240 --> 00:07:39,144 or the structure name as a prefix. 153 00:07:39,144 --> 00:07:42,420 Right, let's have a look at an example in our project. 154 00:07:42,420 --> 00:07:44,500 So we'll start off with main.rs 155 00:07:45,390 --> 00:07:48,640 which defines a sub bunch of submodules in mytypes. 156 00:07:49,704 --> 00:07:52,770 And in particular there's a submodule called employee, 157 00:07:52,770 --> 00:07:54,960 which is defined in employee.rs, 158 00:07:54,960 --> 00:07:56,700 that's where our structure is gonna be. 159 00:07:56,700 --> 00:07:59,460 And then we'll have the usage of it in demo_associated_data 160 00:08:00,823 --> 00:08:02,580 and then we'll run the application. 161 00:08:02,580 --> 00:08:06,660 Okay, so from the top in main.rs, 162 00:08:06,660 --> 00:08:09,840 define mytypes as a module. 163 00:08:09,840 --> 00:08:11,460 Let's not forget uncomment the code 164 00:08:11,460 --> 00:08:12,510 we're gonna be using. 165 00:08:13,350 --> 00:08:16,230 When we define a mytypes module, as we know, 166 00:08:16,230 --> 00:08:20,160 it'll look for mytypes.rs, and in mytypes.rs, 167 00:08:20,160 --> 00:08:24,420 I define a second division module called employee. 168 00:08:24,420 --> 00:08:26,220 Okay, so as we've said before, 169 00:08:26,220 --> 00:08:28,380 if you are in a file called mytypes, 170 00:08:28,380 --> 00:08:30,390 I need to find a submodule, then it look 171 00:08:30,390 --> 00:08:34,530 in the folder called mytypes to find that submodule, 172 00:08:34,530 --> 00:08:35,583 and here it is. 173 00:08:36,840 --> 00:08:40,320 So here's my employee submodule, 174 00:08:40,320 --> 00:08:42,540 got some things being introduced into scope, 175 00:08:42,540 --> 00:08:44,310 and here's my employee structure. 176 00:08:44,310 --> 00:08:46,740 Notice the data now is private, 177 00:08:46,740 --> 00:08:48,990 it's only accessed inside this file, 178 00:08:48,990 --> 00:08:51,420 which is the correct approach, encapsulated, 179 00:08:51,420 --> 00:08:52,980 the structure itself is public, 180 00:08:52,980 --> 00:08:57,120 so I can access the employee name, the data type, 181 00:08:57,120 --> 00:08:59,370 but I can't access the fields externally. 182 00:08:59,370 --> 00:09:02,040 Only in this file can I access the fields. 183 00:09:02,040 --> 00:09:03,150 So that's encapsulation, 184 00:09:03,150 --> 00:09:06,330 that's the equivalent of private data in other languages. 185 00:09:06,330 --> 00:09:11,304 Here's my variable associated data, that's only visible, 186 00:09:11,304 --> 00:09:13,590 that's not public either. 187 00:09:13,590 --> 00:09:16,200 I could have made it public actually if I wanted to, 188 00:09:16,200 --> 00:09:18,630 but I haven't, it's just an internal implementation detail, 189 00:09:18,630 --> 00:09:21,960 so that can only be accessed in the current file. 190 00:09:21,960 --> 00:09:24,801 My implementation for employee defines 191 00:09:24,801 --> 00:09:27,261 constant associated data. 192 00:09:27,261 --> 00:09:30,840 And let's see what we've got here. 193 00:09:30,840 --> 00:09:33,150 The to_string function, I don't think there's anything 194 00:09:33,150 --> 00:09:34,830 particularly interesting there. 195 00:09:34,830 --> 00:09:38,610 It receives an immutable reference to self, 196 00:09:38,610 --> 00:09:39,960 it returns a string. 197 00:09:39,960 --> 00:09:43,113 The string will contain, oh, notice the ID here. 198 00:09:43,950 --> 00:09:46,980 So it'll return the ID inside square brackets 199 00:09:46,980 --> 00:09:50,970 just to make it look nice followed by the person's name, 200 00:09:50,970 --> 00:09:54,210 how much the person earns, and their full-time status. 201 00:09:54,210 --> 00:09:56,040 Okay, so that's the data there. 202 00:09:56,040 --> 00:09:58,984 There's a mutable payrise method 203 00:09:58,984 --> 00:10:03,600 where you attempt to give the person a salary increment 204 00:10:03,600 --> 00:10:06,810 but if the salary now exceeds the maximum salary, 205 00:10:06,810 --> 00:10:09,720 max salary was the constant defined 206 00:10:09,720 --> 00:10:11,820 inside my employee scope. 207 00:10:11,820 --> 00:10:16,020 Okay, so inside my employee block, I defined max salary. 208 00:10:16,020 --> 00:10:19,100 The value will just be effectively copy and pasted in 209 00:10:19,100 --> 00:10:21,060 at the compile time. 210 00:10:21,060 --> 00:10:22,770 So if the salary is more than 99 K, 211 00:10:22,770 --> 00:10:25,560 then reset the salary to 99 K. 212 00:10:25,560 --> 00:10:27,720 Here instead of using the name 213 00:10:27,720 --> 00:10:31,620 of the structure type employee, you can always use Self 214 00:10:31,620 --> 00:10:35,970 as in with a capital S as an alias for the type 215 00:10:35,970 --> 00:10:37,860 of the current structure. 216 00:10:37,860 --> 00:10:41,370 So I could have said Self, look in my own type 217 00:10:41,370 --> 00:10:43,350 to find the maximum salary, 218 00:10:43,350 --> 00:10:46,770 look in my own type to find maximum salary there. 219 00:10:46,770 --> 00:10:49,920 Okay, so not something that you'd probably want to do 220 00:10:49,920 --> 00:10:52,020 at this point, but like I said, when we get on to looking 221 00:10:52,020 --> 00:10:56,309 at traits and generics later on, being able to self-identify 222 00:10:56,309 --> 00:10:58,290 like that is actually quite a useful sentence. 223 00:10:58,290 --> 00:11:01,789 So self with a lowercase s is a reference 224 00:11:01,789 --> 00:11:04,650 to the actual object, Self for the capital S is an alias 225 00:11:04,650 --> 00:11:06,540 for the current structure type. 226 00:11:06,540 --> 00:11:08,760 So I could have actually just said employee 227 00:11:08,760 --> 00:11:10,983 if I preferred to make it more explicit. 228 00:11:11,944 --> 00:11:16,944 Okay, and then finally we have our associated function, new, 229 00:11:17,310 --> 00:11:20,097 build a function, takes in the person's name 230 00:11:20,097 --> 00:11:23,466 and salary and boolean, returns an employee, 231 00:11:23,466 --> 00:11:28,466 it uses the associated static data here, 232 00:11:28,924 --> 00:11:32,250 okay, which is kind of a global scope in this file. 233 00:11:32,250 --> 00:11:34,650 So not prefixed by the structure type. 234 00:11:34,650 --> 00:11:38,379 NEXT_ID fetch the current value and add one. 235 00:11:38,379 --> 00:11:42,930 So initially it's 0, so it'll fetch the value 0 236 00:11:42,930 --> 00:11:45,930 and increment it, so that would be 1, 237 00:11:45,930 --> 00:11:47,880 and that would be the ID. 238 00:11:47,880 --> 00:11:49,920 And that's the ID for the first employee. 239 00:11:49,920 --> 00:11:52,320 So the first time I call new, 240 00:11:52,320 --> 00:11:54,990 the ID will be 1 for that employee 241 00:11:54,990 --> 00:11:56,910 and obviously the second time I call new 242 00:11:56,910 --> 00:12:00,240 for the next employee, its ID will be 2, 243 00:12:00,240 --> 00:12:04,710 and then the third time the ID will be 3, and so on. 244 00:12:04,710 --> 00:12:06,540 Okay, so let's look at the actual usage 245 00:12:06,540 --> 00:12:07,990 of that demo_associated_data. 246 00:12:10,260 --> 00:12:14,370 So I create three employees. 247 00:12:14,370 --> 00:12:17,940 Employee one is Matthew, who earns 10,000, 248 00:12:17,940 --> 00:12:22,940 and employee two is Mark and he earns 20,000. 249 00:12:23,088 --> 00:12:28,088 Luke earns 30,000, and John earns 40,000. 250 00:12:30,600 --> 00:12:35,160 And John is mutable and subjected to a handsome pay rise. 251 00:12:35,160 --> 00:12:38,940 He earns it, you know, so Matthew, Mark, Luke, and John, 252 00:12:38,940 --> 00:12:41,910 you know those names, let's print those details out. 253 00:12:41,910 --> 00:12:44,670 I hope this example works because this is the last example 254 00:12:44,670 --> 00:12:47,570 now in the lesson, it would be nice if it actually worked. 255 00:12:52,320 --> 00:12:55,470 Okay, so remember that the ID was output 256 00:12:55,470 --> 00:12:57,510 in square brackets just for readability. 257 00:12:57,510 --> 00:13:01,227 So the NEXT_ID mechanism that we had here, 258 00:13:01,227 --> 00:13:04,770 this NEXT_ID was rolled over each time. 259 00:13:04,770 --> 00:13:06,840 Each time we created a new employee, 260 00:13:06,840 --> 00:13:08,580 the NEXT_ID was incremented 261 00:13:08,580 --> 00:13:11,460 in a thread safe kind of way to keep the compiler happy. 262 00:13:11,460 --> 00:13:15,888 So the first employee has ID 1, oh, and ID 0, 263 00:13:15,888 --> 00:13:20,888 and then ID 1, and then ID 2, and then ID 3, okay, 264 00:13:21,150 --> 00:13:24,450 plus the details for each employee like so. 265 00:13:24,450 --> 00:13:26,949 So that wraps up the lesson. 266 00:13:26,949 --> 00:13:30,660 Just a very quick reminder of what we've covered. 267 00:13:30,660 --> 00:13:33,540 Defining structures with fields. 268 00:13:33,540 --> 00:13:35,070 We knew that already. 269 00:13:35,070 --> 00:13:38,040 Defining the implementation block for a structure, 270 00:13:38,040 --> 00:13:39,810 which is a kind of a strange concept 271 00:13:39,810 --> 00:13:41,400 when you're first getting into this. 272 00:13:41,400 --> 00:13:45,120 The fact that you define the data in the structure block 273 00:13:45,120 --> 00:13:47,730 and the implementation in another block takes a bit 274 00:13:47,730 --> 00:13:50,100 of getting used to but it is the way to do it. 275 00:13:50,100 --> 00:13:51,930 And then in the implementation block, 276 00:13:51,930 --> 00:13:55,290 functions can be defined as public, 277 00:13:55,290 --> 00:13:58,188 if you want them to be publicly visible or not. 278 00:13:58,188 --> 00:14:01,380 Most functions will be methods. 279 00:14:01,380 --> 00:14:05,100 They have a self reference, either mutable or not. 280 00:14:05,100 --> 00:14:07,470 You can have associated functions 281 00:14:07,470 --> 00:14:08,820 that basically like statics, 282 00:14:08,820 --> 00:14:11,645 they don't have a self pointer, typically they access 283 00:14:11,645 --> 00:14:14,520 or they create an instance, then return it. 284 00:14:14,520 --> 00:14:16,800 And then finally we talked about the idea 285 00:14:16,800 --> 00:14:19,800 of having static data, effectively static data 286 00:14:19,800 --> 00:14:22,980 that's constant, you define inside the implementation block 287 00:14:22,980 --> 00:14:26,100 as constant and then you access it by the class name 288 00:14:26,100 --> 00:14:27,930 or the structure name. 289 00:14:27,930 --> 00:14:29,790 Static data that can vary, 290 00:14:29,790 --> 00:14:32,430 you define outside the implementation block 291 00:14:32,430 --> 00:14:36,270 with a static keyword, and then you can access those 292 00:14:36,270 --> 00:14:40,170 without the class or the structure prefix here. 293 00:14:40,170 --> 00:14:42,810 Okay, so now that we've seen structures, 294 00:14:42,810 --> 00:14:43,643 what we're gonna look at 295 00:14:43,643 --> 00:14:47,823 in the next lesson is how to define interfaces or traits.