Rust for TypeScript Developers Iterating Through a Text File
Transcript from the "Iterating Through a Text File" Lesson
[00:00:31] You can see how that works. So, really, this is just more fine grained control of when these things happen, that's all it is. Now we're gonna do a simple exercise. Let's create a file called lines in our project, and I want you to grab these ones right here.
[00:00:45] Okay, I'm gonna copy this. It's Hello, front end masters, how 123 are you? We're gonna use this kind of throughout our time. I'll have it highlighted for a second. I'll let you guys type it in. Remember, the act of typing and doing is really good for you. If you have the website, it'll be a lot easier cuz you can just copy and paste it really quickly.
[00:01:10] All right, I'm gonna jump over and put it in right now. So I'm gonna go in here. And in the top level, I'm gonna create lines and I'm just gonna paste it in, there we go. Hello fem how are you? With 123 in the middle. So what I want you to do is, I want you to read this file lines, and I want you to print out each line individually, starting in TypeScript.
[00:01:31] I think you all probably can do that mildly easy. If you're familiar enough with Node, it's pretty straightforward. If you're not, you're gonna need to import fs and read file sync probably easily, easy enough to use. So I assume everyone had enough time to do this TypeScript, so let's go in here.
[00:01:49] I'm gonna jump in here, and I'm gonna jump over to my TypeScript file. I'm gonna read in the file and I'm gonna do exactly what I said, I'm gonna print out each line. So I'm gonna do something like this. Import, my goodness, import fs from "fs". Const data = fs.readFile, we'll just use Sync, there we go.
[00:02:09] And I'll say ("lines"). And let's call toSTring and split on the new line. There's actually a reason why I'm doing this. Yeah, I forget. TypeScript, let's say, when you have the dot on that side, there we go. So, there we go, we've created our data. That's every single line in our file.
[00:02:29] And then I can just go, let's see, .forEach, that way. And of course, that will take in a line and then I can console.log (line). There we go, and we don't need that, beautiful. So we read our file, we create it into a string cuz it's a buffer.
[00:02:48] If you don't know, Node writes it out as a buffer. We create it into a string or splitting into a new line. And then we're forEach over every single line. That makes sense, right? So I'm gonna go over here and I'm gonna jump in here and go npx ts-node.
[00:03:02] Just make sure I actually did it and we should see. Hello fem how 123 are you, awesome. So there we go. We've now written this in TypeScript. Hopefully, everyone got this, it's pretty straightforward. Nothing too tricky going on here. I think everyone could probably, in their head, think about how all these functions work.
[00:03:20] Maybe other than two string on a buffer, that's something. Something magical is happening underneath the hood in v8 langth, creating references and boxed values and garbage collection and all that fun stuff. But you pretty much get it. So we're gonna do the same thing except this time, look at that, I even wrote almost the identical same code except for file C.
[00:03:37] I did that, dang ding it, all right? So let's do the exact same thing in Rust. Should be pretty easy, right? All right, so I'm gonna walk you through this. We're gonna do it together one step at a time. Cuz it's gonna introduce a couple values that were not used to say.
[00:03:56] So let's go over to our Rust file. You can delete the contents, everything in there, dcl fast, I deleted that, then by the way, if you didn't know. So let's first get our file. So I'm gonna like this, let file = std::, that's the standard library, fs. It's named the same as Node.
[00:04:14] And then, ::read_to_string. And let's pass in lines, exact same named file, there we go. Now, unfortunately, we haven't quite covered it yet. This is a result of string error. Why is it a result? Why could this error?
>> File might not exist?
>> Boom, file might not exist.
[00:04:33] There could be an error with the operating system. Something just has. Shit happens in your code, that's what happens, okay? Life's, it's never 100% guaranteed even if we have the file. So I'm gonna go this, unwrap, sorry, for cursing, it just felt the right word for it. So there we go.
[00:04:48] I'm just gonna call then wrap. Our program will explode if it doesn't exist, but hey, this is a toy program, unwrap's fine, remember? All right, so there we go, we have the string. So now we can go like this, file.lines(). So that's effectively the same thing as, a split a little different in how it operates, but it's almost the same thing.
[00:05:09] It creates an iterator for us, and now I can do .for_each. So this will allow me to go over every single line and I can print it out. Now again, we use our closure syntax, which is gonna be, bar our variable name bar, and I can go println, two little squirrely braces, line.
[00:05:28] And there we go. We've now gone over our file, split it into lines and for each turn. Now these are exceptionally different how they behave but the end result is the same. And we're gonna go over why they're so different here in a moment. And hopefully, I can show you why iterators are so magical.
[00:05:48] Cuz they are really, really cool. They just, it's hard to explain. Again, remember, the goal of this course is to be as practical as possible. So we're really just trying to get you guys to use Rust, not to learn everything possible about Rust. All right, so there we go.
[00:06:04] So if I go cargo run, I should see the same thing. Hello fem how 123 are you, fantastic. All right, let's go back here and so complete code. My goodness, identical. So, now let's do this. Every other line, I want you guys to implement every other line in TypeScript.
[00:06:23] That's what I want you to print. So here, I'm gonna do it, I'm gonna jump over to TypeScript and I'm gonna add in a filter, right? Cuz that's effectively how you would do it. I'd have to take x and I wanna filter not on x, not on the line, I'll just call that an underscore, but on the index.
[00:06:42] I wanna take every other line. So we're gonna take the index and I'm gonna go i modulo 2 = 0, three equals cuz that's the language we use, and there we go. We're now printing every other line. Hopefully, everyone kinda got that, first try, straightforward. And now we'll do that old npx, run it, and you'll see that I printed every other line.
[00:07:02] Hello how 2 are, awesome. So let's do the exact same thing in Rust. So let's, let me proceed this thing right here. So there you go, complete code, identical again, I'm a genius. All right, we'll do the exact same thing in Rust, but we need to use enumerate cuz we need the indices.
[00:07:18] And then we can use filter. So let's do that now. I'll walk you through it at the same time. So, remember, lines is an iterator. If you were to look at this, it would tell you about how you now have an iterator, fantastic. So I'm gonna do this, .enumerate.
[00:07:34] This will now give me every single index. Okay, then I'm gonna do a filter. And let's go, we're gonna pattern match this out. So I'm gonna say, hey, I know this is a tuple coming in cuz I'm using enumerate. So index is the first value. And then we don't care about the line cuz the line doesn't matter what's on the line.
[00:07:54] So we're just gonna put underscore right here. If you don't put underscore, Rust will warn you that you have an unused variable. So underscores denote to it that anything that starts with an underscore means that it's okay not to be used. So we'll just put an underscore right there, another bar.
[00:08:08] And you can check its types if you want to. Hover over index, you'll see it's a reference to usize, which is, of course, the enumerate. And if you'll hover over this one, it's a reference to string. Okay, that makes sense. Or it's a str. Technically, it's not a reference to a string, it's a str, they're slightly different.
[00:08:23] There's a good reason why, blah, blah, blah, we'll get there. All right, if idx modulo 2 = 0, we're good, we're gonna print this out. Uh-oh, we have an error, let's look at the error. The errors are really good in Rust. Look what it says, a tuple of usize &str doesn't implement the display trait, therefore, we can't display it this way.
[00:08:44] So you can try pretty printing it with the man having a pipe symbol. I don't, I still don't have a good name for it, or we need to convert it. So what I'm gonna do is, I'm gonna like this, I could do .1 for the line cuz, remember, the index is first and then the string.
[00:09:00] Or I could pattern match it out and go, well, I don't care about the index, I just want the line. And there we go, I am now printing out every other line. Cuz remember, enumerate creates a tuple, index, your original type. So if we go into here and we run cargo, same output.
[00:09:20] We're geniuses, all of us.