Check out a free preview of the full Polyglot Programming: TypeScript, Go, & Rust course

The "Using the Projector CLI in Go" Lesson is part of the full, Polyglot Programming: TypeScript, Go, & Rust course featured in this preview video. Here's what you'd learn in this lesson:

ThePrimeagen walks through setting up and using the Go Projector CLI built throughout this course. Creating the projector, saving the config, and implementing and running the previously created operations are covered in this segment.


Transcript from the "Using the Projector CLI in Go" Lesson

>> It should feel very exciting here. We have finished off the TypeScript version, now it's time to do the same thing but in Go. Again, this should go pretty dang quick. No pun, actually intentional there. It just works out, that's how good Go is, it just naturally can be a pun without even trying.

All right, so let's go to our projector main. It looks like we actually went a little bit further in this file, we at least have up to the config being used. So let's do the same thing. Let's create the projector. After creating the projector, let's do the one of the three operations.

And then that's it. We're gonna have to create the little save. So proj equals, of course, projector, at this point, I've already forgot what it was called. There it is. It's called the config, perfect. And now we can go like this, if config, by the way, have you spotted where Rust is gonna blow up yet?

I've asked about the exact same point twice now. So just think about this, we've programmed them all the same way using all the same types. Do you see where Rust is gonna blow up yet? If you do, if you even think you might, try to take a guess.

So I wanted to add this in because I actually think it's a pretty fun game, you're exercising your thought. Remember, what makes Rust hard, it's about who owns a value, correct? So, look at how we're passing around values.
>> Config and the borrowed checker.
>> [SOUND] All right, so yes, the config is gonna become a very high point of contention when we get to Rust.

So let's find out what happens at the very end. Very, very exciting. All right, for now, let's pretend like our problems don't exist, that's how I live my personal life, let's do it now. All right, projector, if it's projector.Print, or remember, we kinda have this two-stage operation, right?

If length(config.args) == 0, well, we need to print out everything. So let's just use our beautiful fmt.Print. Not even newline, just a straight up print, print a beautiful s here, do a little v. And of course, we need to do something more than this, right? We can't just print it out, we can't just JSON stringify it.

So unfortunately, we have to do this whole thing here, where we actually get out the value, then we have to marshal it into JSON or into byte array and then convert that into a string. So let's just do that right now. Let's first start off with data :=, of course, proj.getValueAll.

Now that we have that, we need to do a little error, and I believe it's json.Marshal, right, is Marshaler? Whoops, it's not Marshaler. My neighbor's name is Marshall. Let's me see, Marshal returns that JSON encoding of v, right? Okay, good, so we're gonna go D. And of course, it returns an error, so we do need to handle this error, right?

So we're gonna have the JSON string right here, and there we go. So if we have an error, what should we do here? My guess is we should probably fatal, cuz how else? If that happens, which it should never happen. Really, if this was Rust, we could put some sort of unreachable, there's an unreachable macro that just says this line of coach should never be reached.

Cuz that's effectively what it is. It's just like, this line should never be reached, all right. I'm sure there's a version of this in Go. I just don't know it off the top of my head, so there we go. So let's go like this, string(jsonString), beautiful. Because if you don't know, jsonString, of course, is a byte array, it's a UTF-8 encoded byte array or likely UTF-8.

I assume JSON can't have non UTF-8, I assume it has to be UTF-8 stuff in there. And so that should just work out. Awesome, we've just crushed it. We're done with that side of the print. Again, this whole if else thing, I don't really like if elses. Let's go proj.GetValue.

And then let's just simply get the config.Args[0], value and ok, remember that? Fantastic, right, which means we can actually just go if, pop that thing up there. Do a little semicolon, hit the ok on there. And so now we also have our other condition. Very nice, we don't have to have yet more if statements flying around everywhere.

If that's the case, let's just yank that, paste that, and of course, do a little value right there. Yes, all right, there we go. Operation print, fantastic. Else if, they don't like that. They do not like that. I think last time I just used a series of if statements.

I don't know why I don't like else if, it just feels sometimes really frustrating. So we're just gonna keep on just not using it. Why not? I don't know. It's one of those weird things. Let's see, there we go. Let's have an Add. So again, we're gonna have to write the save operation here shortly.

It should be pretty much as simple as the TypeScript version. So let's jump in here and go, let's see, proj.SetValue and then go config.Args[0], config.Args[1]. Fantastic, right, we have now set the value. Now we just simply need to save. Save is not currently in operation. I think we're all okay with that.

Exact same thing here. Remove that fv up, RemoveValue. Awesome, so now let's just write the final thing we're gonna have to write today in Go, the save operation. (p *Projector), Save(). Now, what are the chances Save's gonna return an error? Well, it's actually gonna be pretty high. So let's just throw the word error in there.

I just would assume that an error can be returned at any moment here because it's Go and we're working with the file system. So let's first go like this. Will go base or dir, of course, is gonna be p.config.config and then we're gonna go path, just like earlier, and do Dir.

Remember that, that just gives us the directory to our config. Once we have that, we need to see, does this thing exist? Now with Go, of course, it's going to be err := os.Stat, right? Yeah, stat. And then we're gonna pass in, of course, the dir. And now we need to find out, does this thing not exist?

Well, there's a function called os.IsNotExist, [LAUGH] it's beautiful name. Tell me that is not a beautiful name. IsNotExist, there we go, we have it, it even has the bang inside of the name, awesome. So we've now found this thing doesn't exist, let's create it. os.Mkdir, and those they have two have them, Mkdir and MkdirAll.

This one simply makes all the directories recursively, that's the one we want. And so let's do that and we're gonna go dir, and of course we need the permissions, a permission of course is gonna be use octal. In coding, if you don't know what octal encoding is, it just works in, I believe, TypeScript as well, and in fact most languages.

If you start a number with 0, a leading 0, it's actually a base 8 number. Just like if you do 0x, it's a base 16 number. This one's a base 8 number, so I'm just gonna go 755, let's give some great permissions, right? That's just great permissions. Everyone's really happy about those permissions.

I know plenty of permissions and those are great permissions. All right, so let's do this. If there is an error, well, we need the return error, right, cuz this is bad. Non-boolean, does not equal nil, right? So, if we found a problem, we couldn't make the directory, that's just all there is to it.

Notice that we don't even really, I'm not sure if we really even get the chance. I assume path.MakedirSync will just throw an error if it can't do it. That's my assumption, so we're just gonna assume that's true. Here we have to handle it right away. Awesome, so we have the directory.

It has been made. Let's just simply write out the file. We don't need to do anything fancy here. We can just simply do a WriteFile, which takes the path, the bytes, and of course the permissions. So let's do this again, which means we need the JSON encode, correct?

Correct, so let's go like this, jsonString, err := json, is it Marshall? Yeah, it is Marshal, always gets me every time. I don't know why that confuses me, the difference between Marshal and, anyways I'm. There we go, beautiful. We have the error handled, we handled the error if we can't do that, p.config.Config and of course pass in the jsonString, and everybody's favorite permission, 755.

I was gonna make it 420, but I feel like that's not a very useful permission set, so we're gonna keep it as 755. Awesome, and of course, whoopsies, return nil. Awesome, we have done it. We've written the save method. It's very simple to do. And now we need to do, of course, the [SOUND] part that's gonna be, it feels like we got a lot of pressure here to perform, so let's get it.

So the first thing you wanna do is let's provide a config and let's use our present working directory and let's just do conf.json, right? And so after that, let's just print everything out. Okay, awesome. By the way, that was really fast. Notice that it just both compiled it and ran it, very impressive.

So let's do a foo, nothing. Awesome, let's do an add foo bar. I think that's just a new line, yeah. Okay, that's just a new line, luckily that was just new line by my cursor, not by the program, or else I'd be very sad. Here, let's just do it right there.

Perfect, okay. Go run again. All right, we're geniuses, we've done this.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now