 Now let's look at the Hangman program we wrote in GoPidgin and let's translate it into real Go. And so here's the contains any function we wrote. And in Go, the things that are changing here is that first off for your function, the parameters are in parentheses, and you separate your parameters by commas. This is a parameter s of type string, parameter called chars, which is a slice of strings. And we're returning the bool, all of the type names in this case, beginning with lowercase loaders. And the equivalent of our force is called for range, you strangely put the range word here, at the end before the thing, which were for ranging over. And another difference is that in the GoPidgin code, we had variables i and j, which we didn't use, but the GoPidgin compiler didn't care about that. It just let us have unused variables, the Go compiler is much more picky. And so we have to use the blank identifier to say that, well, yeah, normally there should be a variable there, but we don't care about it in this case, we're not going to use it. So we use the blank identifier instead to effectively discard those values. And another difference is that in GoPidgin, we can't use for each on strings, we had to use charge slice to get a slice of the individual characters of strings from our from our string. And then we could use for each on that. But in actual go, we can for range over a string. And when we do so, the individual values you get what we're what's being assigned to CH here is what's called a rune. It's actually just a 32 bit integer value, but we call them runes, and it's the it's the number representing that individual Unicode character. But it's not a string, it's an integer. And so what that means is down here in the inner loop, when we range over charge and charge is a slice of strings. So CH two is an actual string. And we want to do an equality comparison between CH and CH two, but they're different types. And the compiler is not going to like it if we try and compare two things of a different type, if you do an equality comparison, they have to be the same kind of thing. And so we can take our rune value though the value CH and turn it into a string by using string like a function, just like we did in go pigeon, we use type names like operators. Well, it looks like a function called go. But anyway, so this is taking rune value CH and getting the string equivalent, and then doing a quality comparison with CH two. So that's our contains any function. Notice the use of curly braces for all of our loops in the body. And then also if has curly braces surrounding its body. Again, indentation doesn't matter, we could like mess all this up and it would still be equivalent, probably wouldn't care. But of course, for good style, you should stick to the normal indentation style. Put everything back. Oops, there we go. Okay, and then looking at the join function here. Here's the version in go pigeon. And then here's the go code. First thing we do is we're checking if the length of strings is equal to zero. And we have and the Len operator in go, they don't call it an operator, they call it a built-in function. But it really is just like an operator. It's just syntactically when you use it, it looks like a function call. And so that's getting the length of the strings slice. And if the length is equal to zero, then we return an empty string. Here we're declaring our variables s and last index. And s is initialized to be an empty string. And last index is initialized to be the length of strings minus one. But as we saw earlier, we can leave the type of these variables inferred because they're being initialized. So we don't have to say this is the string, the compiler can look at this and say, of course, it's a string, because that's what you're signing to s. And we don't have to say the last index is an int because the length of strings minus one, the compiler knows this is an int expression. So it's going to be an int. And then instead of using var here at all, most go programmers would instead just write colon equals. And same thing here. And that's standard style. Okay, and then looking at the forage loop here, the for range equivalent, again, we don't care about the index. So instead of having an index variable I, we just use the blank identifier. All we care about are the values which we store in v. And again, we don't have to specify the types in our forage loops in the go page. And we had to specify that the index variable is always an integer. And we had to specify what kind of thing the value was. But in actual go, we don't. That's why the syntax uses colon equals, because it's implying that the types are left inferred. Anyway, and then over here, for what we're ranging over, well, in the go pigeon code, we used the slice operator to get a slice from our string slice, a smaller slice. So we took everything from strings starting at zero up to but not including last index, we're doing the same thing in go code, except the way that's denoted is with suffix square brackets. And you put the starting index before colon, and the end index after a colon. And in fact, in this case, as a shorthand, if the starting index is zero, we can leave that inferred, we don't have to write the zero there. I'm just going to put it back here though for clarity. And then inside the loop. Oops, I made a sake here, we don't actually need to take v and make it a string because it's already string compiler didn't mind that it was just redundant, it was totally necessary. Anyway, the way you can catenate strings and go is with the plus sign, just like you're adding numbers. But the compiler knows that the things aren't numbers, it knows their strings, so it knows you want to do concatenation. So this is concatenating v and the separator string, and then concatenating that with s and storing the result in s, this is actually just shorthand for s equals s plus v plus separator. So it's taking all these things together and concatenating them and storing them in s. Finally, we have a return statement where we're taking s and concatenating it with from strings, the value at last index for a slice and also for arrays, the equivalent of the get operator is written with square brackets with no colon inside. When you have a colon inside, this is a slice operation like here. But if you have no colon, and there's just one one value, that's in a get operation, but we wouldn't call it that and go and go we would say this is an index operation. Okay, now looking at the get letter function, it's a function which has a parameter found, which is a slice of strings, and the function returns a string. And then we have these two variables letter and alphabet that are both strings. And we don't actually need to declare them like this alphabet, we could just hear when initializing it, use that colon equal syntax. And then same deal for letter down here where it's being assigned to because it's very importantly in this case, letter is only used inside the loop. And the way variable declarations work is if you declare a variable inside a pair of curly braces, it's only visible within that pair of curly braces. So if we tried to use like if we wanted to like use letter down here, the compiler would not like this because as far as the compiler is concerned, this variable declared here only exists within these pair of curly braces. So this would now not be valid. If we wanted the variable to exist throughout the whole function, we would have to put that declaration back up here. And then it could exist throughout the whole function. But in this case, we only use letter inside these curly braces inside the loop. So we can put the declaration inside the loop. And also notice that instead of while we we just write for there's no reserved word while and go, we just use the word for for all of our loops and go, the condition is true, we have a pair of curly braces. And then we're getting the length of the letter, see if it's equal to one. And then our condition here is two parts connected by an and operation, this is the and operator. And it has a lower precedence than the quality operator here. And this function calls done first as well. So these two things are evaluated. And then the and operation is performed. And if the result of the and is true, then we enter the loop. So this is first testing if the length of letter is equal to one. And this is calling the contains any function, passing in the alphabet string, and then also a new slice of strings with just one individual string inside, which is letter letter again is a string. And so this is creating a slice of strings with just one single string in it. Again, we call a function, and you have multiple arguments, you separate the arguments by commas. So contains any here has two arguments, the first alphabet, and the second, this slice of strings, the update found function here has a first parameter found, which is a slice of strings, a second parameter word, which is a string, a third parameter letter, which is a string, and it returns a Boolean. And we start off declaring a variable complete of type Boolean. And again, we could write this as just one statement here to claim a variable complete of type Boolean with the initial value true, but we can leave the type inferred, and we can go even further and just use the colon equals syntax. So this is how most any go programmer would write this. And then we have our for range loop, we're looping over the so called runes of the string word runes, the individual characters of the string represented as integer values. And in this case, we do actually want the index, so we'll have a variable i here rather than the blank identifier. And we're testing if letter is equal to the rune as a string, we have to convert it to a string so we can do in the inequality comparison here. And if so, instead of the set operator to modify values within an array or slice, instead we do an assignment. And the target of our assignment is an indexing operation, we're indexing into found at index i, but we're not retrieving that value instead, we're modifying the value at that location. And we're modifying it to be letter. So it's a little strange because what we did as a set is instead, a kind of assignment as far as goes concerned. And then the next if statement, we are retrieving the value at index i of found. And if it is equal to this string with a single underscore, then we will assign to complete the value false. And then after the loop, we return the value of complete. Okay, so now let's look at our main function. And our main function is making use of two new imported packages, the math rand package and the time package both in the standard go library math rand is a package with a bunch of functions for generating random numbers. And time is a package for reading the system clock and for dealing with time values states and times. And down in the main function, we need those because we have this variable words, which is declared to be a slice of strings with this initial value with all these words inside it. And we want to randomly select a word from this slice. So we need to generate a random index from zero, which would be the first up to eight, up to an including eight, which would be the last word, we need a random number between zero and eight inclusive. And there was no built in rand float operator or anything like that, like there was in go pigeon, instead, we need to use the rand package. And rand package has this function int n, which, given a integer value returns in random number from zero up to that number. So line of words is nine. So if we call rand int n with the value nine, we'll get a random number that's somewhere in the range of zero to eight, which is what we want. And that random number we get back will be stored in index. The problem is that the way the rand package works is that well, the way random number generators work is they're not really random. They start from an initial seed value. And from there, they use complicated math formulas to generate a sequence of numbers that appears from that point to be random. That's that's very chaotic from that point, but it's deterministic. So every time you use these functions, and you start with the same seed, you get the same sequence of numbers. And so we need to set our seed so that every time our program runs, it's going to be different. And so the obvious solution to that is to use the current date and time and use that as our seed, because time advances always. And so as long as our system clock is properly always advancing, then every time we run a program, our seed will be different. To read the system clock, to get the current date and time in the time package, there's the now function, which returns a value representing the current time. It's a time value, as it's defined in that package. That's what's being stored in T here. But the seed function here from Rand is expecting this input and in 64, 64 bit integer value, not time value, we need to take the time and get it expressed as an N64 value. We can do that by using the Unix nano method of the time type, time as a method called Unix nano, which returns an N64 value. And that value is the time represented as the number of nanoseconds that have elapsed since midnight January 1, 1970. So here we're calling the Unix nano method on time and the syntax for that looks like calling a function from a package, but that's not what's happening here. Here time dot now, that's the now function from package time, Rand dot seed, that's the seed function from package Rand, Rand dot intent, that's the intent function from from the Rand package. But to call a method, what we did in GoPigeon is we had a special operator for an MC, they specified the name of the method and then the the type itself, which has the the method that argument is the first argument, and then any other arguments in this case aren't any other arguments just T itself. But the way it's denoted and go is that you have what would be the first argument in GoPigeon, that's actually goes before the dot, and then you have the name of the method, and then you have parentheses, and if there are other arguments, they go inside those parentheses, just like you're calling a function. So it's a little confusing because dot is used in Go to have a few different meanings. The general sense of dot is that if you see x dot y, then you're accessing y from x. And that's the case when you're accessing y, which is something from package x, it's also the case when you're accessing some method y of a value x, or when you're accessing some field y of a struct x. So dot has a few different meanings, but again, the general sense of x dot y is x is something which contains y, and we're accessing y from x. Anyway, moving on. Now we have our random integer index, which we can use to index into words and get back an individual word. And the number of guesses in our program as we established up here is equal to the length of that word. And found here is a variable, which is a slice of strings, and it's initialized with an empty string, because it's just being initialized with the default value for a slice of strings, arguably, some people might write it like this, because that's equivalent. It's just a new variable found, which starts out with the initial value and the size of strings, but let's just keep it this way for consistency. Next, we have a for loop in a special form, which is goes semi equivalent of four ink and four deck that we had in go pigeon. And there are three components here, separate by semicolons, this is the so called precondition. And then we have a semicolon, and then we have the condition semicolon, and then we have the so called post condition. And this is the body of the loop like any other. And what this is semi equivalent to is if we wrote our precondition before the loop, and then a regular loop with just the condition oops, and then we had our body of any number of statements, in this case, just one. And then the post condition is as if it's at the end of the body. So this form here is basically the shorthand for this here, the post condition is executed at the end of the body each time through the loop, the precondition is executed before the loop ever executes. And then the condition, of course, as usual, is just tested each time through the loop. There's only one subtle difference between this form and this form. And the difference is that here in this form, the variable I this counter initializing is in the scope of the loop, meaning it only exists in here. Whereas in this case, we've declared the variable outside the loop and so I is actually existing outside the loop. So in this form, if I try and use the variable I like I'm just say I wanted to print out the variable I, I could do so outside the loop because it still exists out here. It's declared outside the loop, it exists here after the loop. But if I try and do the same thing with this form, like if this were my code, then the compiler gives me an error because I doesn't exist here. So that's a very subtle difference. But it's the only difference. So this is a loop, which we have a counter variable I starts out with a value zero, our condition is I less than the length of the word. And then each time through the loop, we increment I by one. And each time the loop, we're taking our found slice and appending to it, a string with a single character and underscore, and as old as the pen we're signing to found, just like we did up in the original code. The next loop has a condition where we use the greater than operator, this is asking if n guesses is greater than zero. And if so, we enter the loop. And first thing in the function is recalling print line, and we're passing in three arguments. You may recall that earlier when we use print line, we didn't necessarily pass in three arguments, we passed in one or two. So what's going on here, because normally functions have a fixed number of arguments they're expecting, so you can't call them with different number of arguments. Well, print line is a special kind of function called a variadic function, where you can pass in a varying number of inputs. And when we write the prompt function, that'll be a variadic function too. So we'll see how you can create your own variadic functions. Normally, though, functions take a fixed number of arguments. Anyway, so here we're calling get letter passing and found and the result we're signing to this new variable letter, which is local to this loop, because it's declared inside the loop, it doesn't exist outside the loop, but that's okay for our purposes, using this variable letter. And then when we call contains any, the exclamation mark in front, that is the not operator. So contains any returns a Boolean, and this not operation gets us the inverse of whatever contains any returns. And then inside the body, we are documenting and guesses by one, this is again equivalent to if we wrote in guesses equals and guesses minus one, I can't type around my microphone, this is awkward. Or we could also write minus equals one. And this would also be equivalent. But this is the most convenient way to decrement a variable and go. So it's what you'll most commonly see. And then our next if we call update found passing and found word and letter. And if update found returns true, then we will print out this string and then word and return. And lastly, after the loop, we have this called print line with two arguments. So the last piece missing is we need to write our prompt function. But we want a prompt function to be variadic. So let's look just first at variadic functions, by looking at the sum function we wrote and making it very attic. The way we define some is that it's expecting a slice of ints as a parameter nums. And so when we call it, we create a slice events and we pass them in. What we want to be able to do is to find a function sum where instead of passing in a slice of ints, we can just pass in any number of ints zero or more of them, and just have those automatically bundled into a slice, which then is received as a parameter in the function. And the way we can do that is for the last parameter of our function, if it's a slice type, then instead of writing square brackets, we can write ellipses. And now when we call some instead of passing a slice of ints, the compiler is expecting us to pass ints themselves any number of them. And in fact, we can even leave it blank in which case, nums here will be an empty slice. If I just have a single argument three, now it's a slice with one value. If I have another argument, it's now a slice with two values. I had another argument to slice with three values, etc. So just all of these arguments here are bundled into a single slice automatically, it's just a syntax thing, it's just a convenience. And be clear, the the variadic parameter, the special slice parameter can only be the last parameter of your function. So if I had it in other parameters here, like just say s, whatever arbitrary stuff. Now when I call the function, I would, let's say I'd have to pass the string here. So in this case, three would be passed to a high would be passed to s, and four and six would get bundled into a slice of ints, which would be passed to nums. Now the only problem is having made it convenient to pass individual values as a slice without having to explicitly create a slice. Well, what if I have a slice that I want to pass to nums, as I do here, like say I have numbers here, and I want to pass that to nums. Well, I can't just write numbers, the compiler will complain that what it's expecting here is zero or more integers, not a slice of ints. So the way to get around this is you write ellipses after the slice value. So this is my slice events, and I put ellipses after and the and the compiler knows that some is very adequate knows that okay, this is passing the slice itself to nums. So it's a little funny, because we've created this syntactical convenience, but then there are these cases where we have to have a special syntax to fix the convenience, as we do here. Anyway, so that's variadic functions, it's really just a style thing. print line is a variadic function that takes in any number of arguments. So I can pass in any number of things, and all of these values are being bundled into a slice. The question, though, is that you may have noticed print line, we can pass in numbers and actually any sort of value can be passed into print line, because the way print line is defined is this function looks like this. It's one parameter, we don't know what it's good, we don't care what it's called, but it's variadic. And then the type is the so called empty interface type. And the empty interface is equivalent of what and go we called any. It's the special interface type that all values are considered to implement even types that don't normally implement interfaces. And it kind of makes sense that they call it the empty interface, because it's like saying, well, you have this interface, but it has no methods. And so automatically everything would be considered to implement it. Though I do think the way it's written is kind of annoying, I wish they just gave it a proper name instead of writing interface curly braces, but that's how it's written. Anyway, so I'm going to get rid of all this. And we're going to come back here and look at our prompt function. And so looking at the prompt function prompt is defined to be a function that takes in any number of values of type empty interface. So we can pass in whatever we want to this function, and any number of arguments, and they all get bundled into the slice vowels. And first thing we do is we test the vowels is not equal to zero. If so, if there were values passed at the prompt, well, we want to print them out. And we do so by passing the vowels to print line. And remember print line itself is a variadic function, taking any number of empty interface values. And we have this slice of empty interface values, which we want to pass to if we want to pass them as if we're passing them individually, rather than just one big slice. So we use this ellipsis syntax. And then what our prompt function wants to do is read from standard input. And I don't want to get into all the details here, we'll cover the stuff later. But what's happening is first off, most of standard in that is a global variable in the OS package called standard in, which is a handle to the standard input file. Standard input file is the file that you read from when you want to read the text from the console is also standard output, which is what you write to when you want to write out the standard console. And that's what actually print line and the print function do. But we don't have any convenient equivalent of print line in in the Fump package. Unfortunately, there's nothing that conveniently in one function call reads from the standard input. Instead, we have to do so using, well, there's a few ways we can do it. One way to do it is from the Buff IO package is this thing called a scanner, which you pass it in a file, we're passing it in here the standard input file. And it's this thing that when we call it scan method, we get we get back a scanner here, and then we're calling it scan method, and that's going to read from the file up to the first new line, which is what we want in this case, we want the user to type something in the console, then hit enter that enter adds a new line into the text. And that's what we want to get from their text entry. Anyway, so scanner, we call the scan method, notice that it doesn't return anything, it's just internally the scanner is a is a struct that will retain the data that it read from the file. Because we're dealing with a file, we're reading right from a file, there's always potential for something going wrong, there's various things that could go wrong. So we have to check for the error. The scanner has an error method that you should call after calling the scan method. It returns an error value. And that error value is of type error. It's a special built in type called error, which is actually it's an interface type that has a single method called error. So it's something looks like this way to find an interface type in go looks like this. This is defining a type called error, which is an interface, and this interface will have one method called error, which returns a string. And that's it. So this is the whole interface. It's built in the language, you don't actually have to declare this, it's it already exists automatically. It's just a very simple interface type, where it's something you can call its error method, and it gives you back a string. And this is a useful generalization for errors, because when bad things happen, and you want to represent information about what went wrong, you might have very different needs of how to represent that information, the simplest possible solution is just represented as a string. But in other cases, you might need much more elaborate information. So you might create a struct that needs to store a lot more information. But what all errors have in common is that it's useful to have a string representation that we can print out so we can read what the problem was. So that's why the error interface just has a single method called error, which returns a string and a message describing what went wrong. Anyway, so the convention and go is to use this error type to represent all errors. If you have a function that might go wrong, and you need to return an error, instead of using a string, we use this error type. So that's what the scanner type in the standard library does. This error method is returning to the variable err, a value of type error. It's an interface value. And so if it's nil, that means there was no error. If the if error is non nil, then something went wrong. Our function then needs to return the error value. We also have to return a string. But in the case of an error, we don't care what the string is, we'll just return an empty string. Anyway, so that's how we handle errors when we read from the standard input. And then assuming there is no error, then we can get the text that was scanned. Scanners storing the text, having checked for the error as we should do, it's now okay to actually get the text that was read. And that's what we return. And in the event of success, in the event of no error, we return nil for the error value. So that's the convention and go of how to handle errors. And of course, I don't actually really need this variable as I'm just going to do this, get rid of that unnecessary variable. Okay. So having defined prompt to return not just a string, but also an error value, we actually have to go back and make those changes in the code as I already did. So prompt here is now returning two values. The first is assigned a letter, and the second here is assigned to error. And anytime you call a function which returns an error value, you should check if the error is not nil. Because if it's not nil, and there's some kind of error that happened, and then our function should abort. So get letter itself now needs to return not just a string, it also needs to return an error. And the event that prompt returned an error, get letter itself should return that error. And in the event that there is an error, it doesn't matter what get letter returns, it'll just return empty string. And now because get letter returns two values, it returns two things everywhere else where we return, we also have to return two values. And in the event of success, in the event of not an error, we'll just return nil, as we do here, and as we do down here. And now because get letter itself might return an error when it's called, we need to go where it's called down in main, where is it right here. And we store what it returns in letter, and a variable error. And we check if this variable error is not equal to nil. And that means something went wrong, there was some error in reading from the console. And here back up in main is an appropriate place to decide, well, we got this error, and we need to read from console but we can't. So there's nothing really really we can do, we're just going to abort the program. So we're just going to return we we tell the user, hey, something something went wrong reading from the console. And then we abort the program by returning from main. So that's the basic pattern of how we deal with errors and go. And that's the entirety of our hangman program. Let's see if we can get it to run. Hey, something's working. Pick a letter a let's get invalid inputs. It's a spat. No, it's cat. Hey, okay, so our program works cool.