1 00:00:06,600 --> 00:00:07,920 - [Instructor] The Rust library makes 2 00:00:07,920 --> 00:00:10,380 extensive use of generics. 3 00:00:10,380 --> 00:00:13,650 It defines generic structures, generic enums, 4 00:00:13,650 --> 00:00:15,810 such as option and result. 5 00:00:15,810 --> 00:00:19,140 Generic traits and generic functions. 6 00:00:19,140 --> 00:00:21,810 And you can also define your own generic types and functions 7 00:00:21,810 --> 00:00:22,650 in your own code, 8 00:00:22,650 --> 00:00:25,260 and that's what we're going to do in this lesson. 9 00:00:25,260 --> 00:00:26,250 So first of all, 10 00:00:26,250 --> 00:00:28,620 you can define a generic structure like this. 11 00:00:28,620 --> 00:00:31,950 Quite straightforward, similar syntax to many languages. 12 00:00:31,950 --> 00:00:33,840 I define coordinate structure 13 00:00:33,840 --> 00:00:35,970 which holds X, Y, Z coordinates, 14 00:00:35,970 --> 00:00:37,860 but I haven't limited myself 15 00:00:37,860 --> 00:00:39,510 to the type of those values. 16 00:00:39,510 --> 00:00:43,380 I haven't said X and Y and Z are integers or floats. 17 00:00:43,380 --> 00:00:44,213 I've made it generic. 18 00:00:44,213 --> 00:00:47,010 This is a type parameter, T. 19 00:00:47,010 --> 00:00:50,880 X, Y, and Z will be of some type T, okay? 20 00:00:50,880 --> 00:00:52,140 So I don't care. 21 00:00:52,140 --> 00:00:52,973 They could be integers, 22 00:00:52,973 --> 00:00:55,530 they could be floats, I don't care. 23 00:00:55,530 --> 00:00:57,183 It's the same kind of concept. 24 00:00:58,800 --> 00:01:01,830 You can use any type name, not just T. 25 00:01:01,830 --> 00:01:04,710 Generics can have multiple type parameters, 26 00:01:04,710 --> 00:01:05,850 and we'll have a look at that later on. 27 00:01:05,850 --> 00:01:10,260 Like hash map for example, has a key type and a value type. 28 00:01:10,260 --> 00:01:11,790 You just specify multiple types 29 00:01:11,790 --> 00:01:14,220 inside the angle brackets with a comma, 30 00:01:14,220 --> 00:01:16,980 K,V, that kind of syntax. 31 00:01:16,980 --> 00:01:20,760 Right, so it's easy to define a generic structure. 32 00:01:20,760 --> 00:01:22,500 When you instantiate the generic structure 33 00:01:22,500 --> 00:01:24,120 the compiler has to know 34 00:01:24,120 --> 00:01:26,490 what type T is going to be. 35 00:01:26,490 --> 00:01:27,600 One way to do this 36 00:01:27,600 --> 00:01:29,533 is to specify the type parameter explicitly 37 00:01:29,533 --> 00:01:31,740 when you mention coordinate, 38 00:01:31,740 --> 00:01:32,573 and I've done that here. 39 00:01:32,573 --> 00:01:35,550 I've explicitly said, I'm creating a coordinate 40 00:01:35,550 --> 00:01:38,040 where T is i32, 41 00:01:38,040 --> 00:01:40,770 and then obviously I have to give i32 values 42 00:01:40,770 --> 00:01:43,440 for the X, Y, and Z parameters, okay? 43 00:01:43,440 --> 00:01:45,150 So that's explicit typing, 44 00:01:45,150 --> 00:01:49,080 the compiler with bis and instantiate a coordinate of i32 45 00:01:49,080 --> 00:01:51,513 with i32 fields here, here and here. 46 00:01:53,100 --> 00:01:53,968 However, most of the time 47 00:01:53,968 --> 00:01:56,509 you can actually allow a compiler to guess 48 00:01:56,509 --> 00:01:58,110 what the type is going to be 49 00:01:58,110 --> 00:01:59,640 based on the values you supply. 50 00:01:59,640 --> 00:02:01,470 So this syntax would also work. 51 00:02:01,470 --> 00:02:02,730 In the first example, 52 00:02:02,730 --> 00:02:06,660 I explicitly said, T is going to be i32, 53 00:02:06,660 --> 00:02:09,180 but in this case the compiler can guess. 54 00:02:09,180 --> 00:02:13,290 It knows that X, Y and Z will be of type T. 55 00:02:13,290 --> 00:02:15,690 It can see the types of parameters are passed in 56 00:02:15,690 --> 00:02:19,290 so it'll understand that T implicitly is a float. 57 00:02:19,290 --> 00:02:21,000 So X, Y and Z, 58 00:02:21,000 --> 00:02:23,760 probably gonna be float 64 would be my guess. 59 00:02:23,760 --> 00:02:27,120 So in that case, it's actually kind of better in a way 60 00:02:27,120 --> 00:02:29,430 to not specify the type parameter here 61 00:02:29,430 --> 00:02:31,860 and just leave the compiler, guess for itself 62 00:02:31,860 --> 00:02:32,693 what the types are. 63 00:02:32,693 --> 00:02:33,720 I mean if you want to, 64 00:02:33,720 --> 00:02:35,850 you can specify type explicitly, 65 00:02:35,850 --> 00:02:38,970 but in most cases you'll just fall back on implicit typing. 66 00:02:38,970 --> 00:02:40,290 The compiler can guess 67 00:02:40,290 --> 00:02:42,693 what type to instantiate for T here. 68 00:02:43,950 --> 00:02:45,750 Right, well, very simple that, actually. 69 00:02:45,750 --> 00:02:47,160 Let's have a look at an example. 70 00:02:47,160 --> 00:02:51,213 For this lesson, the project is lesson13_generics. 71 00:02:52,230 --> 00:02:56,700 So here it is in the rustdev folder, lesson13_generics. 72 00:02:56,700 --> 00:02:58,690 So let's open that in the code editor 73 00:02:59,580 --> 00:03:00,427 and here we are. 74 00:03:01,590 --> 00:03:04,950 Okay, so we have kind of a simpler structure 75 00:03:04,950 --> 00:03:07,770 than we looked at in the previous few demos. 76 00:03:07,770 --> 00:03:11,490 I've got a main, main file here 77 00:03:11,490 --> 00:03:16,490 which just pulls in various other functions in other files. 78 00:03:16,740 --> 00:03:19,110 Okay, so first off, 79 00:03:19,110 --> 00:03:22,410 we should be looking at a demo of generic structures. 80 00:03:22,410 --> 00:03:23,910 Let's uncomment that statement 81 00:03:25,530 --> 00:03:30,530 and we'll come into it here, demo_generic_structs. 82 00:03:30,630 --> 00:03:32,589 So I've defined a private structure, 83 00:03:32,589 --> 00:03:34,680 just for this module 84 00:03:34,680 --> 00:03:37,290 with private fields, just for this module. 85 00:03:37,290 --> 00:03:38,188 T is a type parameter, 86 00:03:38,188 --> 00:03:41,670 whatever type you wanna call it, T is fine. 87 00:03:41,670 --> 00:03:44,490 First of all, a coordinate, C1 is a coordinate 88 00:03:44,490 --> 00:03:46,465 where T is explicitly a type parameter 89 00:03:46,465 --> 00:03:50,910 is explicitly passed in i32 for T. 90 00:03:50,910 --> 00:03:55,440 So X, Y, and Z will be off type i32 explicitly. 91 00:03:55,440 --> 00:03:57,870 And then using the implicit syntax 92 00:03:57,870 --> 00:03:59,730 where the compiler can guess 93 00:03:59,730 --> 00:04:02,580 that the types are going to be float 64. 94 00:04:02,580 --> 00:04:05,700 And no need for us to specify explicitly the type parameter. 95 00:04:05,700 --> 00:04:07,301 Oh, one thing I will mention, 96 00:04:07,301 --> 00:04:08,940 syntax that might be a bit different 97 00:04:08,940 --> 00:04:10,650 from what you're expecting. 98 00:04:10,650 --> 00:04:13,680 If you are explicitly specifying the type parameter 99 00:04:13,680 --> 00:04:15,360 you have to use a double colon 100 00:04:15,360 --> 00:04:17,434 between the original structure 101 00:04:17,434 --> 00:04:20,970 and the type parameter inside angle brackets. 102 00:04:20,970 --> 00:04:23,100 Okay, and that's probably different syntax 103 00:04:23,100 --> 00:04:25,380 from what you're expecting from other languages. 104 00:04:25,380 --> 00:04:28,290 So for example, in Java and other languages, 105 00:04:28,290 --> 00:04:31,050 you'd specify just that. 106 00:04:31,050 --> 00:04:33,297 You'd say, "I want to coordinate of i32," 107 00:04:34,260 --> 00:04:36,090 but that syntax doesn't work in Rust. 108 00:04:36,090 --> 00:04:38,100 You've gotta put a double colon in the middle. 109 00:04:38,100 --> 00:04:39,570 So that's gonna look a bit odd 110 00:04:39,570 --> 00:04:41,790 if you did get used to initially 111 00:04:41,790 --> 00:04:43,020 but it is required. 112 00:04:43,020 --> 00:04:45,570 The coordinate structure is a generic, 113 00:04:45,570 --> 00:04:48,390 and then you have to put the type parameter 114 00:04:48,390 --> 00:04:50,640 after the colons like so. 115 00:04:50,640 --> 00:04:53,040 Or of course, you can just use implicit type in 116 00:04:53,040 --> 00:04:55,110 like this, okay? 117 00:04:55,110 --> 00:04:56,670 so I'll run the application 118 00:04:56,670 --> 00:04:58,950 just to make sure that's gonna work okay. 119 00:04:58,950 --> 00:05:00,360 And then I'm gonna try something else out 120 00:05:00,360 --> 00:05:01,260 just to see what happens 121 00:05:01,260 --> 00:05:04,410 if I pass in different types for the parameters 122 00:05:04,410 --> 00:05:05,880 for the properties for X, Y and Z. 123 00:05:05,880 --> 00:05:09,690 So first of all, it initializes outputs 124 00:05:09,690 --> 00:05:13,620 the coordinate C1 is integer based. 125 00:05:13,620 --> 00:05:14,730 Yes, indeed. 126 00:05:14,730 --> 00:05:17,790 And then coordinate to C2 uses floating point 127 00:05:17,790 --> 00:05:20,190 numbers 1.1, 2.2, 3.3. 128 00:05:20,190 --> 00:05:21,150 Okay, that's good. 129 00:05:21,150 --> 00:05:22,530 I wonder what would happen 130 00:05:22,530 --> 00:05:24,510 if I actually passed in different types. 131 00:05:24,510 --> 00:05:27,510 So I passed in, they're meant to be the same type, okay? 132 00:05:27,510 --> 00:05:28,770 And the compiler can guess here 133 00:05:28,770 --> 00:05:31,320 that they're float 64, I guess. 134 00:05:31,320 --> 00:05:34,830 What would happen if I passed in an integer 135 00:05:34,830 --> 00:05:37,410 and an integer and a floating point value? 136 00:05:37,410 --> 00:05:38,850 I wonder what would happen then. 137 00:05:38,850 --> 00:05:40,020 What do you think would happen in that case? 138 00:05:40,020 --> 00:05:41,390 Let's see. 139 00:05:41,390 --> 00:05:45,540 Oof, so remember, Rust doesn't do implicit type conversions. 140 00:05:45,540 --> 00:05:47,430 It's kind of confused here. 141 00:05:47,430 --> 00:05:49,680 It saw these as being integers, 142 00:05:49,680 --> 00:05:52,650 therefore it expected Z also to be an integer 143 00:05:52,650 --> 00:05:54,426 and it found a floating point number 144 00:05:54,426 --> 00:05:58,050 and okay, so what about the other way around? 145 00:05:58,050 --> 00:06:03,050 What if it was 1.1, 2.2, and then 3? 146 00:06:04,260 --> 00:06:08,670 Okay, so float, float, integer. 147 00:06:08,670 --> 00:06:11,190 I wonder what would happen now, do you know? 148 00:06:11,190 --> 00:06:12,090 Let's have a look. 149 00:06:12,960 --> 00:06:14,370 Again, an error. 150 00:06:14,370 --> 00:06:17,010 It says, right, so if X is a float 151 00:06:17,010 --> 00:06:18,180 and Y is a float 152 00:06:18,180 --> 00:06:19,860 and they're all meant to be the same type 153 00:06:19,860 --> 00:06:22,693 then surely Z has to be a float as well. 154 00:06:22,693 --> 00:06:24,420 And it isn't a float, it's an integer. 155 00:06:24,420 --> 00:06:26,100 Now you might think, well, 156 00:06:26,100 --> 00:06:29,093 a compiler worth its salt would promote the integer 157 00:06:29,093 --> 00:06:31,440 to a float and we'd get away with it. 158 00:06:31,440 --> 00:06:32,370 Rust doesn't do that. 159 00:06:32,370 --> 00:06:34,710 The Rust is very rigid when it comes to types. 160 00:06:34,710 --> 00:06:36,390 It doesn't do type conversions. 161 00:06:36,390 --> 00:06:38,520 Even simple types like in to float. 162 00:06:38,520 --> 00:06:40,110 So even though it could 163 00:06:40,110 --> 00:06:45,110 in theory convert that to a 3.0 doesn't, it says, right 164 00:06:45,270 --> 00:06:47,670 well hang on Andy, what are you doing? 165 00:06:47,670 --> 00:06:49,380 I was expecting a float to point number 166 00:06:49,380 --> 00:06:50,550 and I found an integer. 167 00:06:50,550 --> 00:06:53,130 So you've gotta be consistent. 168 00:06:53,130 --> 00:06:57,180 If these things really are the same type, then you 169 00:06:57,180 --> 00:07:00,240 really do need to give it the same type everywhere, like so. 170 00:07:00,240 --> 00:07:05,240 So hopefully now it'll work again and we can rest in peace. 171 00:07:05,550 --> 00:07:06,383 There we go. 172 00:07:06,383 --> 00:07:08,970 Okay, so defining generic structures 173 00:07:08,970 --> 00:07:10,320 straightforward enough. 174 00:07:10,320 --> 00:07:12,930 Use T instead of a actual type name. 175 00:07:12,930 --> 00:07:14,190 And then to instantiate 176 00:07:14,190 --> 00:07:16,734 either explicitly specify the type parameter or 177 00:07:16,734 --> 00:07:20,463 leave the compiler guess based on the values it sees.