1 00:00:06,690 --> 00:00:10,230 - Applications often need to read and write data to a file. 2 00:00:10,230 --> 00:00:12,240 For example, our application reads 3 00:00:12,240 --> 00:00:15,360 and writes a file containing CSV data. 4 00:00:15,360 --> 00:00:17,730 Each line, as we've seen in the file, 5 00:00:17,730 --> 00:00:19,440 has this kind of structure, 6 00:00:19,440 --> 00:00:23,910 the startDate, endDate, description. 7 00:00:23,910 --> 00:00:27,390 So our application reads one line at a time, 8 00:00:27,390 --> 00:00:31,860 and each line it puts it into a Visit structure. 9 00:00:31,860 --> 00:00:33,870 We've seen a little bit about this already. 10 00:00:33,870 --> 00:00:35,970 The Visit structure contains the start date 11 00:00:35,970 --> 00:00:38,850 and the end date and the description as fields 12 00:00:38,850 --> 00:00:41,010 as read in from the file. 13 00:00:41,010 --> 00:00:42,870 So I guess the first thing we should do is 14 00:00:42,870 --> 00:00:46,653 to take a look at the Visit structure in types.rs. 15 00:00:47,550 --> 00:00:49,743 So here we are in types.rs, 16 00:00:50,580 --> 00:00:52,710 amongst all the other details, 17 00:00:52,710 --> 00:00:54,360 we have the Visit structure. 18 00:00:54,360 --> 00:00:57,090 It stores the start date as a NaiveDate. 19 00:00:57,090 --> 00:01:00,090 Remember, NaiveDate represents a date 20 00:01:00,090 --> 00:01:01,590 without time zone information. 21 00:01:01,590 --> 00:01:03,060 That's why it's naive. 22 00:01:03,060 --> 00:01:04,380 It's not that naive really. 23 00:01:04,380 --> 00:01:08,040 It's a date object without timestamp. 24 00:01:08,040 --> 00:01:11,250 The start_date and the end_date and the description. 25 00:01:11,250 --> 00:01:13,560 Couple of points to note here, 26 00:01:13,560 --> 00:01:15,540 from a coding quality point of view, 27 00:01:15,540 --> 00:01:18,930 the structure is public, because obviously, 28 00:01:18,930 --> 00:01:21,180 I'm gonna be using that structure extensively 29 00:01:21,180 --> 00:01:22,620 in the application. 30 00:01:22,620 --> 00:01:24,930 But do you notice that the fields aren't public? 31 00:01:24,930 --> 00:01:26,460 This is encapsulation. 32 00:01:26,460 --> 00:01:28,200 These fields aren't public. 33 00:01:28,200 --> 00:01:29,610 In other words, they're private. 34 00:01:29,610 --> 00:01:32,610 They can only be accessed in the code in this file, 35 00:01:32,610 --> 00:01:34,170 and that's proper encapsulation. 36 00:01:34,170 --> 00:01:37,110 It would be the equivalent of declaring private fields 37 00:01:37,110 --> 00:01:41,700 in a class in Java or C# or C++. 38 00:01:41,700 --> 00:01:43,980 The other point I wanna make while I'm here 39 00:01:43,980 --> 00:01:47,010 is the NaiveDate structure type 40 00:01:47,010 --> 00:01:49,260 is defined in the chrono crate. 41 00:01:49,260 --> 00:01:52,980 Whenever you've got a crate that starts, that isn't std, 42 00:01:52,980 --> 00:01:54,840 then you have to basically add this 43 00:01:54,840 --> 00:01:57,570 as a dependency into your TOML file. 44 00:01:57,570 --> 00:02:01,080 The standard library is standard and it's already included, 45 00:02:01,080 --> 00:02:05,430 but any additional crates you've gotta specify, like chrono, 46 00:02:05,430 --> 00:02:07,530 you've gotta add into your dependencies. 47 00:02:07,530 --> 00:02:11,670 So in Cargo.toml, I've added chrono as a dependency. 48 00:02:11,670 --> 00:02:14,190 So when the application runs the first time 49 00:02:14,190 --> 00:02:16,890 or when you build it, it'll have to fetch. 50 00:02:16,890 --> 00:02:19,500 Well, fetch the latest version of chrono 51 00:02:19,500 --> 00:02:22,020 or a version number that you specify 52 00:02:22,020 --> 00:02:24,240 into your current application folder. 53 00:02:24,240 --> 00:02:25,500 And then once you've done that, 54 00:02:25,500 --> 00:02:28,530 you can then use that chrono package. 55 00:02:28,530 --> 00:02:31,773 So let's go back into types.rs. 56 00:02:33,060 --> 00:02:35,400 Here is my Visit structure containing the start_date, 57 00:02:35,400 --> 00:02:37,470 the end_date, and the description. 58 00:02:37,470 --> 00:02:38,580 So I create one 59 00:02:38,580 --> 00:02:41,430 of those objects every time I read another line 60 00:02:41,430 --> 00:02:43,170 of text from the file. 61 00:02:43,170 --> 00:02:44,760 So let's take a look 62 00:02:44,760 --> 00:02:48,000 at how we can read CSV data from a file. 63 00:02:48,000 --> 00:02:50,280 We'll have a look at fh.rs. 64 00:02:50,280 --> 00:02:52,200 That's our file handling module. 65 00:02:52,200 --> 00:02:54,753 And there's a function read_visits_from_file. 66 00:02:56,130 --> 00:02:58,230 Okay, let's take a look at that. 67 00:02:58,230 --> 00:02:59,283 So in fh, 68 00:03:00,750 --> 00:03:01,583 here we are. 69 00:03:01,583 --> 00:03:04,350 It's a public function, read_visits_from_file. 70 00:03:04,350 --> 00:03:07,740 It takes the name of the file like data.txt, 71 00:03:07,740 --> 00:03:11,010 and it returns a vector of Visit, 72 00:03:11,010 --> 00:03:14,910 where Visit is defined in the types module. 73 00:03:14,910 --> 00:03:17,973 Remember, what the crate keyword means in Rust? 74 00:03:18,960 --> 00:03:22,380 Generally, your application is gonna have lots of modules. 75 00:03:22,380 --> 00:03:24,900 At the very top level in your application, 76 00:03:24,900 --> 00:03:26,370 right at the top of your crate, 77 00:03:26,370 --> 00:03:30,240 it defines a module called types, okay? 78 00:03:30,240 --> 00:03:33,840 So technically the crate or the main code I should say 79 00:03:33,840 --> 00:03:37,290 is at the root namespace in your application, 80 00:03:37,290 --> 00:03:40,650 and types is like a sub namespace, okay? 81 00:03:40,650 --> 00:03:42,240 So underneath your crate, 82 00:03:42,240 --> 00:03:45,540 you've created effectively a namespace called types. 83 00:03:45,540 --> 00:03:48,873 In order to use that module or that namespace elsewhere, 84 00:03:50,070 --> 00:03:51,390 like in file handling, 85 00:03:51,390 --> 00:03:56,390 we say crate is a shorthand for the root folder 86 00:03:56,670 --> 00:03:58,710 or the root namespace in our application, 87 00:03:58,710 --> 00:04:02,070 go to the top level namespace of our project, 88 00:04:02,070 --> 00:04:06,090 and then give me the types sub namespace, okay? 89 00:04:06,090 --> 00:04:09,120 So from the top, give me access to the types namespace. 90 00:04:09,120 --> 00:04:11,460 What I could have done is I could have gone further 91 00:04:11,460 --> 00:04:15,270 and said ::Visit, okay? 92 00:04:15,270 --> 00:04:19,170 And in that case, this name would be in scope directly. 93 00:04:19,170 --> 00:04:22,410 And then I wouldn't have to say types::Visit. 94 00:04:22,410 --> 00:04:24,390 I could just say Visit, 95 00:04:24,390 --> 00:04:27,420 and Visit, like that. 96 00:04:27,420 --> 00:04:29,940 So depends which you prefer. 97 00:04:29,940 --> 00:04:31,500 Sometimes it's actually, 98 00:04:31,500 --> 00:04:33,090 sometimes I find it preferable 99 00:04:33,090 --> 00:04:36,310 to actually include the module name as a prefix 100 00:04:37,200 --> 00:04:40,560 and not to import the actual structure directly. 101 00:04:40,560 --> 00:04:43,770 So it's this name now that's in scope. 102 00:04:43,770 --> 00:04:46,020 And it's that name you have to use as a qualifier 103 00:04:46,020 --> 00:04:49,200 to say in that module, give me the Visit type, okay? 104 00:04:49,200 --> 00:04:52,410 So you can see that the Visit type came from that module 105 00:04:52,410 --> 00:04:54,783 and then you know where to look to find it. 106 00:04:55,830 --> 00:04:57,450 Anyway, one way or the other, 107 00:04:57,450 --> 00:05:01,020 the read_visits_from_file function returns a vector 108 00:05:01,020 --> 00:05:02,040 of Visit objects. 109 00:05:02,040 --> 00:05:03,933 So let's take a look in here. 110 00:05:04,830 --> 00:05:09,570 Notice that there are two different modules involved here. 111 00:05:09,570 --> 00:05:14,507 In the std::fs, that's the standard file system module, 112 00:05:15,600 --> 00:05:17,460 there's a File structure. 113 00:05:17,460 --> 00:05:20,040 And then in the std::io module, 114 00:05:20,040 --> 00:05:23,250 there are lower level structures and traits 115 00:05:23,250 --> 00:05:25,320 that I'm gonna describe now. 116 00:05:25,320 --> 00:05:28,950 So we are talking about how to read from a file, okay? 117 00:05:28,950 --> 00:05:31,373 So obviously at this point it's the BufReader. 118 00:05:31,373 --> 00:05:36,060 BufReader is a structure, and BufRead is a trait, 119 00:05:36,060 --> 00:05:37,500 and you'll see why in a moment. 120 00:05:37,500 --> 00:05:40,170 So first of all, you say File::open, okay? 121 00:05:40,170 --> 00:05:43,200 So from the std::fs::File, 122 00:05:43,200 --> 00:05:45,570 File::open, give it the file name. 123 00:05:45,570 --> 00:05:49,260 And that returns a result, a result enum, 124 00:05:49,260 --> 00:05:51,723 could be okay, could be an error. 125 00:05:52,620 --> 00:05:54,780 If I was in any doubt about this working, 126 00:05:54,780 --> 00:05:56,100 I would have a match statement 127 00:05:56,100 --> 00:05:59,370 to say match okay, match error. 128 00:05:59,370 --> 00:06:00,870 I'm not gonna bother doing that, 129 00:06:00,870 --> 00:06:02,760 I'm just gonna unwrap it, okay? 130 00:06:02,760 --> 00:06:04,110 If there was any possibility 131 00:06:04,110 --> 00:06:05,550 that this could actually fail, 132 00:06:05,550 --> 00:06:08,070 then I'd put that into a match statement instead, 133 00:06:08,070 --> 00:06:10,170 but I'm fairly confident that's gonna work. 134 00:06:10,170 --> 00:06:14,820 And it gives you back a file handle basically, here. 135 00:06:14,820 --> 00:06:17,280 And then what you do is you pass that file handle 136 00:06:17,280 --> 00:06:18,960 into a BufReader. 137 00:06:18,960 --> 00:06:21,123 Lots of languages have a similar kind of API. 138 00:06:21,123 --> 00:06:23,910 BufReader, that'll create a new BufReader, 139 00:06:23,910 --> 00:06:27,450 which can read lines of text from that file. 140 00:06:27,450 --> 00:06:31,260 So here is my BufReader object, right? 141 00:06:31,260 --> 00:06:36,210 Then, oh, I create a vector of Visits. 142 00:06:36,210 --> 00:06:38,700 I'm gonna be adding Visit objects into that vector. 143 00:06:38,700 --> 00:06:41,070 Every time I read a line of text, 144 00:06:41,070 --> 00:06:43,800 I'll convert it into a Visit object, 145 00:06:43,800 --> 00:06:45,663 and I'll add it into this vector. 146 00:06:46,680 --> 00:06:50,790 So take in my BufReader that I created, you can iterate. 147 00:06:50,790 --> 00:06:54,150 It has a function called lines, which is an iterator. 148 00:06:54,150 --> 00:06:57,300 Basically it'll give you back one line at a time, okay? 149 00:06:57,300 --> 00:06:59,850 So it'll give you back a line. 150 00:06:59,850 --> 00:07:03,780 And that line, I unwrap it, okay, 151 00:07:03,780 --> 00:07:06,480 to give me back a string, it could issue a result. 152 00:07:06,480 --> 00:07:09,510 So I unwrap it, that'll give me back a string. 153 00:07:09,510 --> 00:07:14,510 And then you know like start_date, end_date, description. 154 00:07:15,090 --> 00:07:16,830 And I pass that string 155 00:07:16,830 --> 00:07:19,860 into a function in my Visit structure, 156 00:07:19,860 --> 00:07:21,360 a factory function, 157 00:07:21,360 --> 00:07:24,870 which will create a Visit from a string. 158 00:07:24,870 --> 00:07:27,300 It's kind of like a parse string function. 159 00:07:27,300 --> 00:07:31,020 It parses the string, it grabs the start_date, the end_date, 160 00:07:31,020 --> 00:07:34,350 and the description, and it puts it into a Visit object. 161 00:07:34,350 --> 00:07:35,183 And then it returns it. 162 00:07:35,183 --> 00:07:36,780 We'll have a look at that function a bit later. 163 00:07:36,780 --> 00:07:40,920 I wanna avoid all the date stuff just for now. 164 00:07:40,920 --> 00:07:43,080 We'll get back to that later. 165 00:07:43,080 --> 00:07:44,850 It creates a Visit object based 166 00:07:44,850 --> 00:07:47,010 on the line of text that we just read in. 167 00:07:47,010 --> 00:07:50,447 And then we push that Visit into my vector of all Visits. 168 00:07:50,447 --> 00:07:52,890 And at the end, I just return all the Visits. 169 00:07:52,890 --> 00:07:55,560 Remember in Rust, a function that ends 170 00:07:55,560 --> 00:07:58,140 in an expression is like a return statement. 171 00:07:58,140 --> 00:08:00,540 So I could have said return Visits, 172 00:08:00,540 --> 00:08:01,380 and that would've been fine. 173 00:08:01,380 --> 00:08:03,360 You might prefer to write it that way 174 00:08:03,360 --> 00:08:06,513 or a rusty crustacean would write it that way. 175 00:08:07,890 --> 00:08:11,490 Now this one particular point I wanna mention here, 176 00:08:11,490 --> 00:08:12,900 in the code we've just looked at, 177 00:08:12,900 --> 00:08:15,870 you can see that the File structure is used. 178 00:08:15,870 --> 00:08:17,853 So you can see why I've imported that. 179 00:08:18,738 --> 00:08:21,060 And you can also see the BufReader structure 180 00:08:21,060 --> 00:08:24,333 is being used, so you can see why I'm using that. 181 00:08:25,530 --> 00:08:29,460 But no matter how hard you look in the code here, 182 00:08:29,460 --> 00:08:32,100 it doesn't actually seem to use BufRead. 183 00:08:32,100 --> 00:08:33,573 What on earth is BufRead? 184 00:08:34,440 --> 00:08:38,550 Maybe it was a mistake, maybe I could just delete it, okay? 185 00:08:38,550 --> 00:08:40,410 Well, it wasn't a mistake. 186 00:08:40,410 --> 00:08:43,210 Look, see what happens if I try to compile the code now. 187 00:08:45,960 --> 00:08:48,780 This is quite subtle, but it's a kind 188 00:08:48,780 --> 00:08:51,660 of mistake you will doubtless make at some point. 189 00:08:51,660 --> 00:08:52,593 I have for sure. 190 00:08:55,680 --> 00:08:57,090 Right. 191 00:08:57,090 --> 00:09:01,920 So this BufReader, okay, which has a lines method, 192 00:09:01,920 --> 00:09:06,003 it's saying this BufReader doesn't have a lines method, 193 00:09:07,680 --> 00:09:08,930 but what's going on here? 194 00:09:11,790 --> 00:09:13,530 How is that even work? 195 00:09:13,530 --> 00:09:15,813 And I tell you what the answer is. 196 00:09:16,710 --> 00:09:19,143 We looked at this when we talked about traits. 197 00:09:20,820 --> 00:09:22,900 So the first fact is BufReader 198 00:09:23,940 --> 00:09:28,200 implements a trait called BufRead, okay? 199 00:09:28,200 --> 00:09:30,958 And I can show you the documentation for that. 200 00:09:30,958 --> 00:09:31,980 BufReader. 201 00:09:31,980 --> 00:09:34,890 The names of these things aren't great in the library. 202 00:09:34,890 --> 00:09:38,490 BufReader implements the BufRead trait. 203 00:09:38,490 --> 00:09:41,040 Let me show the documentation to prove that point. 204 00:09:41,040 --> 00:09:43,770 Here's the documentation for the BufReader structure 205 00:09:43,770 --> 00:09:46,410 in the std::io module. 206 00:09:46,410 --> 00:09:50,283 You can see that BufReader does implement the BufRead trait. 207 00:09:51,171 --> 00:09:52,338 Okay, so what? 208 00:09:53,307 --> 00:09:55,320 Let's have a look at the BufRead trait. 209 00:09:55,320 --> 00:09:58,470 If you skim down, this is the implementation 210 00:09:58,470 --> 00:10:01,290 of the BufRead trait for BufReader. 211 00:10:01,290 --> 00:10:04,290 If you scroll down just a little bit, you'll notice 212 00:10:04,290 --> 00:10:09,290 that the lines method is actually part of the BufRead trait. 213 00:10:09,840 --> 00:10:13,410 The BufReader structure implements this trait, 214 00:10:13,410 --> 00:10:16,620 therefore, it implements the lines method. 215 00:10:16,620 --> 00:10:19,410 But the thing is, if you in your code, 216 00:10:19,410 --> 00:10:22,710 in your outside code, if you invoke a method, 217 00:10:22,710 --> 00:10:25,920 which is implemented via a trait on that structure, 218 00:10:25,920 --> 00:10:26,880 not only do you have 219 00:10:26,880 --> 00:10:31,080 to include the structure type in your code, 220 00:10:31,080 --> 00:10:35,130 you've also gotta include the trait as well, okay? 221 00:10:35,130 --> 00:10:37,590 Even though you're not using the trait yourself, 222 00:10:37,590 --> 00:10:39,420 you're calling the lines method. 223 00:10:39,420 --> 00:10:42,690 And the lines method is included in BufRead, okay? 224 00:10:42,690 --> 00:10:45,330 It's part of the BufReader implementation. 225 00:10:45,330 --> 00:10:49,350 So that's a surprise for most developers 226 00:10:49,350 --> 00:10:50,640 in other languages. 227 00:10:50,640 --> 00:10:54,840 I've gotta actually say if BufReader implements BufRead, 228 00:10:54,840 --> 00:10:56,730 and if I call any of the methods 229 00:10:56,730 --> 00:10:58,350 that are actually defined in there, 230 00:10:58,350 --> 00:10:59,790 then I have to include that trait 231 00:10:59,790 --> 00:11:01,800 in my list of imports as well. 232 00:11:01,800 --> 00:11:04,620 I can't just include the BufReader trait, 233 00:11:04,620 --> 00:11:06,090 the BufReader structure. 234 00:11:06,090 --> 00:11:07,320 I've gotta also include 235 00:11:07,320 --> 00:11:10,200 or import the BufRead trait that it implements. 236 00:11:10,200 --> 00:11:11,943 So when I call the lines method, 237 00:11:13,170 --> 00:11:14,850 the compiler basically has to know 238 00:11:14,850 --> 00:11:18,390 that the lines method complies with what's defined in there. 239 00:11:18,390 --> 00:11:20,790 So import the structure, 240 00:11:20,790 --> 00:11:23,730 plus if you use any methods in that structure, 241 00:11:23,730 --> 00:11:25,020 which come from a trait, 242 00:11:25,020 --> 00:11:27,360 then you have to import the trait as well. 243 00:11:27,360 --> 00:11:29,460 A very subtle point there. 244 00:11:29,460 --> 00:11:30,293 That's the sort of thing, 245 00:11:30,293 --> 00:11:31,920 you're gonna scratch your head over for a while. 246 00:11:31,920 --> 00:11:35,460 I certainly did when I was learning Rust myself. 247 00:11:35,460 --> 00:11:38,070 So let me just do a quick cargo check to make sure 248 00:11:38,070 --> 00:11:40,803 that I've reinstated the code in its spit state, 249 00:11:43,020 --> 00:11:44,043 cargo check. 250 00:11:45,600 --> 00:11:47,160 Now it's good. 251 00:11:47,160 --> 00:11:48,690 So the next thing we're going to look at is 252 00:11:48,690 --> 00:11:51,300 to write CSV data to a file. 253 00:11:51,300 --> 00:11:52,710 It's in the same source file. 254 00:11:52,710 --> 00:11:55,020 It's the write_visits_to_file function. 255 00:11:55,020 --> 00:11:56,817 Let's a look at that now. 256 00:11:56,817 --> 00:11:59,010 Okay, so write_visits_to_file. 257 00:11:59,010 --> 00:12:00,750 This is more straightforward actually. 258 00:12:00,750 --> 00:12:04,410 It takes the file name, data.txt. 259 00:12:04,410 --> 00:12:06,450 It takes the vector of Visits 260 00:12:06,450 --> 00:12:08,910 that it needs to write to a file. 261 00:12:08,910 --> 00:12:12,840 So in the file structure in the standard library, 262 00:12:12,840 --> 00:12:16,710 there's an associated function, a static function basically. 263 00:12:16,710 --> 00:12:21,710 It creates a new file, that returns a result enum, 264 00:12:21,780 --> 00:12:24,360 which could be okay or it could be an error. 265 00:12:24,360 --> 00:12:26,580 So I'm assuming it's gonna be okay. 266 00:12:26,580 --> 00:12:28,500 And I just unwrap the object. 267 00:12:28,500 --> 00:12:29,940 If it had been an error, 268 00:12:29,940 --> 00:12:31,560 my program would've crashed at that point. 269 00:12:31,560 --> 00:12:33,180 It would've panicked. 270 00:12:33,180 --> 00:12:35,820 If I had any doubt at all that it could crash, 271 00:12:35,820 --> 00:12:37,020 then I wouldn't just unwrap it, 272 00:12:37,020 --> 00:12:40,200 I'd say match okay or error. 273 00:12:40,200 --> 00:12:42,060 Anyway, it gives you back a file handle. 274 00:12:42,060 --> 00:12:44,040 And in a similar kind of way, 275 00:12:44,040 --> 00:12:47,490 you create a BufWriter upon that file. 276 00:12:47,490 --> 00:12:52,490 Here's my BufWriter object, called writer. 277 00:12:52,950 --> 00:12:55,290 I iterate through each of my Visits. 278 00:12:55,290 --> 00:12:56,913 Visits is just my vector. 279 00:12:57,750 --> 00:13:00,330 I iterate and get back each Visit structure, 280 00:13:00,330 --> 00:13:01,620 a reference to it, 281 00:13:01,620 --> 00:13:06,180 and then I write each structure to file. 282 00:13:06,180 --> 00:13:09,720 Using my BufWriter, I call the write_all method. 283 00:13:09,720 --> 00:13:13,860 By the way, the write_all method is defined in this trait. 284 00:13:13,860 --> 00:13:16,113 So BufWriter implements Write. 285 00:13:16,980 --> 00:13:19,380 And when you call it a method defined in the Write trait, 286 00:13:19,380 --> 00:13:22,410 you've gotta include the Write trait in your code. 287 00:13:22,410 --> 00:13:24,540 If I didn't include that, I'd get the same kind 288 00:13:24,540 --> 00:13:27,900 of error I had when I didn't include that, okay? 289 00:13:27,900 --> 00:13:30,690 So a structure which implements a trait, 290 00:13:30,690 --> 00:13:33,420 if you call any of those methods from the trait, 291 00:13:33,420 --> 00:13:35,550 you have to include that trait as well. 292 00:13:35,550 --> 00:13:38,130 And anyway, we write all the Visits. 293 00:13:38,130 --> 00:13:42,360 So here we go, Visit is an object. 294 00:13:42,360 --> 00:13:43,560 As we'll see later on, 295 00:13:43,560 --> 00:13:45,420 it's got a two string function 296 00:13:45,420 --> 00:13:47,850 and I just converted to bytes, okay? 297 00:13:47,850 --> 00:13:51,210 The file writer is expecting bytes not characters, 298 00:13:51,210 --> 00:13:53,640 because characters are quite tricky in Rust. 299 00:13:53,640 --> 00:13:56,460 A character could be one byte, like the letter H, 300 00:13:56,460 --> 00:13:59,220 or it could be four bytes, like a smiley face. 301 00:13:59,220 --> 00:14:00,750 So we have to convert it 302 00:14:00,750 --> 00:14:03,693 into primitive bytes that can then be written to the file. 303 00:14:05,160 --> 00:14:07,500 Not surprisingly, whenever you're doing file handling, 304 00:14:07,500 --> 00:14:08,880 it could fail. 305 00:14:08,880 --> 00:14:11,970 And remember, the way that Rust indicates possible failure 306 00:14:11,970 --> 00:14:13,560 is via the result enum. 307 00:14:13,560 --> 00:14:14,970 It doesn't throw an exception, 308 00:14:14,970 --> 00:14:18,240 it just returns a result, which may be an error. 309 00:14:18,240 --> 00:14:20,250 So I've just unwrapped the result 310 00:14:20,250 --> 00:14:22,080 in the hope and the assumption that it's okay. 311 00:14:22,080 --> 00:14:24,150 And again, in like proper code, 312 00:14:24,150 --> 00:14:26,610 you wouldn't just unwrap it, you'd have a match. 313 00:14:26,610 --> 00:14:29,610 Match okay? Okay, no problem. 314 00:14:29,610 --> 00:14:32,040 Match error? That's an exception basically. 315 00:14:32,040 --> 00:14:34,380 And then you have to do some recovery process. 316 00:14:34,380 --> 00:14:36,630 So looking quite a lot there actually, 317 00:14:36,630 --> 00:14:38,040 mostly to do with file handling, 318 00:14:38,040 --> 00:14:43,040 and a reminder about the weird world of Rust structures 319 00:14:43,200 --> 00:14:44,793 and how it implements traits.