1 00:00:06,660 --> 00:00:08,850 - A common requirement in programming is to display 2 00:00:08,850 --> 00:00:11,730 the contents of an object on the console. 3 00:00:11,730 --> 00:00:12,660 Here's one approach. 4 00:00:12,660 --> 00:00:16,077 I've got a simple structure called coord with longitude 5 00:00:16,077 --> 00:00:17,940 and latitude. 6 00:00:17,940 --> 00:00:20,640 I've implemented in the coordinate structure, 7 00:00:20,640 --> 00:00:22,170 I've implemented a function, 8 00:00:22,170 --> 00:00:24,300 I've chosen to call it to_string, 9 00:00:24,300 --> 00:00:26,970 nothing special but the name. 10 00:00:26,970 --> 00:00:30,390 It takes a coordinate, and it uses the format macro, 11 00:00:30,390 --> 00:00:33,300 remember it basically builds a formatted string containing 12 00:00:33,300 --> 00:00:36,273 the longitude and the latitude. 13 00:00:36,273 --> 00:00:39,480 That formatted string gets returned. 14 00:00:39,480 --> 00:00:41,670 So, I could invoke the to_string function like this, 15 00:00:41,670 --> 00:00:44,490 in my code I could say a chord dot two-string, 16 00:00:44,490 --> 00:00:46,950 and it'll basically print out the longitude 17 00:00:46,950 --> 00:00:48,783 and the latitude like so. 18 00:00:49,830 --> 00:00:51,420 Right, well, that would work, 19 00:00:51,420 --> 00:00:54,810 but a better approach in Rust that's more kind of in keeping 20 00:00:54,810 --> 00:00:56,430 with the Rust philosophy, 21 00:00:56,430 --> 00:00:59,160 there's an interface or trait called display, 22 00:00:59,160 --> 00:01:03,750 which basically is invoked when you output objects like so. 23 00:01:03,750 --> 00:01:06,330 So, the display trait has a single function 24 00:01:06,330 --> 00:01:09,120 called fmt format. 25 00:01:09,120 --> 00:01:11,040 It takes a reference to the object 26 00:01:11,040 --> 00:01:14,430 whatever implements this display trait, like coordinate. 27 00:01:14,430 --> 00:01:17,163 It also takes an object called a formatter. 28 00:01:18,120 --> 00:01:22,320 The formatter provides an API to help you do the formatting. 29 00:01:22,320 --> 00:01:24,840 One of these objects gets created for you automatically, 30 00:01:24,840 --> 00:01:27,870 as you'll see, and effectively it returns a result. 31 00:01:27,870 --> 00:01:30,843 It's the string result that you want to then display. 32 00:01:31,710 --> 00:01:33,930 Right, so this trait, you can implement this trait 33 00:01:33,930 --> 00:01:35,730 in your structures like this. 34 00:01:35,730 --> 00:01:39,660 My coordinate structure can implement the display trait. 35 00:01:39,660 --> 00:01:42,330 Therefore, it has a format function, 36 00:01:42,330 --> 00:01:45,060 it receives a reference to the coordinate, 37 00:01:45,060 --> 00:01:49,140 and it receives a format object, and it returns a result. 38 00:01:49,140 --> 00:01:51,870 If you do implement the display trait, 39 00:01:51,870 --> 00:01:53,760 therefore if you have a format function, 40 00:01:53,760 --> 00:01:57,720 then you can output a coordinate just by saying this. 41 00:01:57,720 --> 00:01:59,760 You can just say a code, 42 00:01:59,760 --> 00:02:02,310 and internally the compiler will convert 43 00:02:02,310 --> 00:02:04,890 that into a call to the format function. 44 00:02:04,890 --> 00:02:08,340 So, if you write a code like this 45 00:02:08,340 --> 00:02:10,800 and you pass it into the default formatter, 46 00:02:10,800 --> 00:02:13,350 internally the compiler will convert this 47 00:02:13,350 --> 00:02:14,700 into a statement like this. 48 00:02:15,780 --> 00:02:16,710 It'll take your coordinate object, 49 00:02:16,710 --> 00:02:20,029 and it'll implicitly call the format function. 50 00:02:20,029 --> 00:02:22,590 It'll pass in a formatter object, 51 00:02:22,590 --> 00:02:24,660 which we don't need to worry too much about, 52 00:02:24,660 --> 00:02:25,713 it just happens. 53 00:02:26,910 --> 00:02:29,850 And the idea is that your format function returns a string, 54 00:02:29,850 --> 00:02:31,830 or a result, which is really a string, 55 00:02:31,830 --> 00:02:33,240 and whatever you return, 56 00:02:33,240 --> 00:02:35,250 that's what's gonna be displayed. 57 00:02:35,250 --> 00:02:38,613 So, let's see how to actually do this in practice. 58 00:02:39,960 --> 00:02:42,570 Here is my example. 59 00:02:42,570 --> 00:02:46,410 So, I've imported from the stud format module, 60 00:02:46,410 --> 00:02:50,190 I've imported the display trait, the formatter structure, 61 00:02:50,190 --> 00:02:52,500 and the result structure, which I'll need. 62 00:02:52,500 --> 00:02:55,350 Here's my coordinate, it has a longitude, latitude, 63 00:02:55,350 --> 00:02:58,710 and I've implemented the display trait for coordinate. 64 00:02:58,710 --> 00:03:00,780 In other words, I have a format function. 65 00:03:00,780 --> 00:03:05,780 It receives a coordinate reference plus a mutable formatter, 66 00:03:06,150 --> 00:03:07,680 it returns a result. 67 00:03:07,680 --> 00:03:11,370 So, one technique, there's a macro called write, 68 00:03:11,370 --> 00:03:12,420 and effectively what it does, 69 00:03:12,420 --> 00:03:14,340 it's a bit like writing to a file, 70 00:03:14,340 --> 00:03:18,000 it writes a formatted string into the formatter. 71 00:03:18,000 --> 00:03:20,490 Okay, so the formatter is kind of like the destination 72 00:03:20,490 --> 00:03:23,370 and into that formatter, you can write whatever you want. 73 00:03:23,370 --> 00:03:27,420 I've written a string coord square bracket curly brackets 74 00:03:27,420 --> 00:03:29,790 here would be the longitude these curly brackets 75 00:03:29,790 --> 00:03:32,760 would be the latitude n square bracket. 76 00:03:32,760 --> 00:03:34,920 Okay, so by implementing the format function 77 00:03:34,920 --> 00:03:39,920 like this whenever I output a coordinate it'll use this code 78 00:03:40,020 --> 00:03:40,893 to display it. 79 00:03:42,000 --> 00:03:43,560 Right now, there is another way 80 00:03:43,560 --> 00:03:46,890 to implement the display trait. 81 00:03:46,890 --> 00:03:49,050 The formatter class that we've just been looking 82 00:03:49,050 --> 00:03:51,300 at has some helper methods 83 00:03:51,300 --> 00:03:54,360 to help you build a formatted string. 84 00:03:54,360 --> 00:03:56,820 So, for example, the formatter structure 85 00:03:56,820 --> 00:03:58,770 has a debug list method. 86 00:03:58,770 --> 00:04:03,770 It helps you to generate a string containing the formatting 87 00:04:03,990 --> 00:04:06,540 for a list, like an array. 88 00:04:06,540 --> 00:04:10,020 Technically when you call the debug list function, 89 00:04:10,020 --> 00:04:12,240 it returns a data type called debug list. 90 00:04:12,240 --> 00:04:14,130 I'll talk about that again in a moment. 91 00:04:14,130 --> 00:04:18,810 There's also a function on formatter called debug map. 92 00:04:18,810 --> 00:04:21,510 If you have a hash map, for example, you'd call this method. 93 00:04:21,510 --> 00:04:24,270 You'd say formatter debug map 94 00:04:24,270 --> 00:04:26,220 and it returns a debug map object, 95 00:04:26,220 --> 00:04:28,710 and I'll explain that again in a moment. 96 00:04:28,710 --> 00:04:30,450 There's a debug set. 97 00:04:30,450 --> 00:04:31,320 If you had a set, 98 00:04:31,320 --> 00:04:33,780 like a set that contains distinct collections, 99 00:04:33,780 --> 00:04:36,900 no duplicates, the debug set method 100 00:04:36,900 --> 00:04:39,270 would return a debug set object 101 00:04:39,270 --> 00:04:42,000 which helps you output a set. 102 00:04:42,000 --> 00:04:43,230 There's a debug struct method, 103 00:04:43,230 --> 00:04:44,640 that's what we're going to use. 104 00:04:44,640 --> 00:04:47,833 If you have a structure, you can say formatter.debugstruct. 105 00:04:49,080 --> 00:04:51,150 It'll return a debug struct object, 106 00:04:51,150 --> 00:04:52,980 which helps you format the output, 107 00:04:52,980 --> 00:04:55,080 or the content of a structure. 108 00:04:55,080 --> 00:04:56,850 There's also a debug tuple 109 00:04:56,850 --> 00:04:59,490 which helps you output the content of a tuple. 110 00:04:59,490 --> 00:05:03,060 So, you call one of these methods on your formatter, 111 00:05:03,060 --> 00:05:06,300 and it returns one of these data types debug list, 112 00:05:06,300 --> 00:05:08,820 or debug map or debug something, 113 00:05:08,820 --> 00:05:12,900 and these debug types I've called it debug XXXX here, 114 00:05:12,900 --> 00:05:16,470 these debug structures here all of them have methods 115 00:05:16,470 --> 00:05:19,110 which help you format that type of thing. 116 00:05:19,110 --> 00:05:20,283 So, for example, 117 00:05:21,230 --> 00:05:25,020 debug struct has methods called field and finish. 118 00:05:25,020 --> 00:05:27,930 If you call formatter debug struct, 119 00:05:27,930 --> 00:05:30,000 and you get back one of these objects, 120 00:05:30,000 --> 00:05:32,700 the debug struct type then has these methods 121 00:05:32,700 --> 00:05:35,130 to output the fields of a structure, 122 00:05:35,130 --> 00:05:36,180 and then you can say, 123 00:05:37,230 --> 00:05:38,063 finish when you've finished outputting everything. 124 00:05:38,063 --> 00:05:39,990 It's basically a builder pattern. 125 00:05:39,990 --> 00:05:41,580 So, that might sound a bit abstract. 126 00:05:41,580 --> 00:05:44,580 Let me show you how that actually looks in practice. 127 00:05:44,580 --> 00:05:47,520 This is an alternative implementation for display 128 00:05:47,520 --> 00:05:48,470 for the coordinate. 129 00:05:49,810 --> 00:05:51,870 Here, I've taken the formatter object, 130 00:05:51,870 --> 00:05:54,810 and I've called that debug struct method that I mentioned 131 00:05:54,810 --> 00:05:56,520 on the previous slide. 132 00:05:56,520 --> 00:05:58,080 You can give it like a header 133 00:05:58,080 --> 00:05:59,910 to say it is a coordinate structure. 134 00:05:59,910 --> 00:06:01,230 This is just verbiage. 135 00:06:01,230 --> 00:06:03,750 This is literal output that you want to appear 136 00:06:03,750 --> 00:06:04,583 on the console. 137 00:06:04,583 --> 00:06:06,690 So, this is literally what you want to output. 138 00:06:06,690 --> 00:06:11,310 Coordinate structure, and then you can say there's a field, 139 00:06:11,310 --> 00:06:12,800 and then you can say the name of the field 140 00:06:12,800 --> 00:06:14,820 in whatever text you want, 141 00:06:14,820 --> 00:06:17,760 and then the value that you want to output. 142 00:06:17,760 --> 00:06:20,790 Another field, these strings here are what's going 143 00:06:20,790 --> 00:06:23,040 to appear on the console, 144 00:06:23,040 --> 00:06:26,220 and these are the values to output next to those strings. 145 00:06:26,220 --> 00:06:28,890 So, it'll output coordinate structure, 146 00:06:28,890 --> 00:06:31,230 longitude and the value, 147 00:06:31,230 --> 00:06:34,320 latitude, and the value, and then finish. 148 00:06:34,320 --> 00:06:38,340 Okay, so by calling these methods you're building the output 149 00:06:38,340 --> 00:06:41,160 to appear and then that's what you return. 150 00:06:41,160 --> 00:06:44,160 So, both of those techniques using either the right macro, 151 00:06:44,160 --> 00:06:47,070 or these helper methods to build the format, you know, 152 00:06:47,070 --> 00:06:51,150 step by step, either of those techniques are fine. 153 00:06:51,150 --> 00:06:54,000 So, let's see a look in the project. 154 00:06:54,000 --> 00:06:57,030 We're going to look at the main RS, the entry point. 155 00:06:57,030 --> 00:06:58,560 We'll have a look at the displayable, 156 00:06:58,560 --> 00:07:01,980 that's the structure which implements the display trait, 157 00:07:01,980 --> 00:07:04,650 and then we'll run the demo displayable code 158 00:07:04,650 --> 00:07:06,393 to actually execute the demo. 159 00:07:07,560 --> 00:07:12,560 Okay then, so from the top here's my main code. 160 00:07:12,990 --> 00:07:17,990 We're going to run demo displayable, and, in my structure, 161 00:07:19,110 --> 00:07:21,990 I've got a module called displayable. 162 00:07:21,990 --> 00:07:25,320 Okay, just so that the name of it is fairly obvious. 163 00:07:25,320 --> 00:07:27,030 Here's my coordinate structure, 164 00:07:27,030 --> 00:07:30,060 the data, longitude, latitude. 165 00:07:30,060 --> 00:07:32,160 I've got some regular implementation. 166 00:07:32,160 --> 00:07:33,810 I've just got to build a function 167 00:07:33,810 --> 00:07:37,200 to create a coordinate just to initialize one. 168 00:07:37,200 --> 00:07:39,750 So nothing particularly new there. 169 00:07:39,750 --> 00:07:42,060 And then I've implemented display trait for create. 170 00:07:42,060 --> 00:07:45,480 I've actually got two alternative implementations. 171 00:07:45,480 --> 00:07:47,520 First of all, I've got the implementation 172 00:07:47,520 --> 00:07:49,110 that we looked at first, 173 00:07:49,110 --> 00:07:51,900 where it takes a formatter and it writes 174 00:07:51,900 --> 00:07:54,630 to that formatter whatever string 175 00:07:54,630 --> 00:07:56,490 with whatever values you want to output, 176 00:07:56,490 --> 00:07:58,440 the longitude and the latitude. 177 00:07:58,440 --> 00:08:01,773 So, we'll run the code using this formatter first. 178 00:08:02,610 --> 00:08:05,113 So, demo displayable. 179 00:08:07,680 --> 00:08:08,970 This is the code we're gonna look at. 180 00:08:08,970 --> 00:08:10,120 It creates a coordinate 181 00:08:11,380 --> 00:08:12,450 and then outputs it using the formatter, 182 00:08:12,450 --> 00:08:14,613 using the display trait implementation. 183 00:08:16,800 --> 00:08:20,310 So, at the moment, when I output this object, 184 00:08:20,310 --> 00:08:25,020 it'll call the format function in my display implementation. 185 00:08:25,020 --> 00:08:27,263 And currently, this is the format function 186 00:08:27,263 --> 00:08:28,590 that it's going to see. 187 00:08:28,590 --> 00:08:30,660 And that's what we'll see on the screen. 188 00:08:30,660 --> 00:08:31,983 So, if I say cargo run, 189 00:08:32,940 --> 00:08:35,250 it'll say coordinate, square bracket, 190 00:08:35,250 --> 00:08:39,319 and then the longitude and the latitude, 51 degrees north, 191 00:08:39,319 --> 00:08:41,580 3.9 degrees west. 192 00:08:41,580 --> 00:08:42,720 If I'm not mistaken, 193 00:08:42,720 --> 00:08:45,390 that would be the coordinates of Swansea, 194 00:08:45,390 --> 00:08:47,460 who would have guessed that? 195 00:08:47,460 --> 00:08:48,423 Okay, right. 196 00:08:49,770 --> 00:08:51,720 Well, let's comment out this implementation 197 00:08:51,720 --> 00:08:54,480 and let's uncomment the alternative implementation. 198 00:08:54,480 --> 00:08:58,770 In this one, I'm using the debug struct method 199 00:08:58,770 --> 00:09:02,160 on the formatter and that's the string that will appear. 200 00:09:02,160 --> 00:09:04,530 Followed by these fields with that text 201 00:09:04,530 --> 00:09:07,290 and that's what's going to be output. 202 00:09:07,290 --> 00:09:09,303 So, let's run that now. 203 00:09:10,620 --> 00:09:11,613 Cargo run. 204 00:09:12,690 --> 00:09:15,090 So, this time in my code, 205 00:09:15,090 --> 00:09:19,600 this time when it calls the format method on my coordinate, 206 00:09:19,600 --> 00:09:21,990 it'll be calling this format method 207 00:09:21,990 --> 00:09:24,330 and outputs coordinate structure. 208 00:09:24,330 --> 00:09:27,750 whatever text you pass in here is literally going to appear, 209 00:09:27,750 --> 00:09:29,940 so it's up to you, you could output it in French, or German, 210 00:09:29,940 --> 00:09:32,190 or even Welsh if you knew the words, 211 00:09:32,190 --> 00:09:34,440 and then it outputs longitude field, 212 00:09:34,440 --> 00:09:36,510 and the latitude field using those words there, 213 00:09:36,510 --> 00:09:39,810 so it put the curly brackets in automatically, 214 00:09:39,810 --> 00:09:42,690 and then we just slotted in the text that we want to appear, 215 00:09:42,690 --> 00:09:45,510 and then the value and the text we want to appear, 216 00:09:45,510 --> 00:09:47,160 and the value. 217 00:09:47,160 --> 00:09:51,120 Okay, so this is a very idiomatic way of doing it in Rust. 218 00:09:51,120 --> 00:09:54,690 Rust defines several interfaces or traits which allow you 219 00:09:54,690 --> 00:09:57,630 to hook in to the standard ecosystem 220 00:09:57,630 --> 00:10:00,423 to cause a display formatting like so.