Go Tutorial #8 - Anonymous Functions & Closures

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi guys welcome to another golang programming tutorial on esoteric tech in this video i'm going to be covering how to use functions as values if you're like i was when i first started programming you might find the concept of accepting functions as parameters and returning functions from other functions to be somewhat confusing i know i did even though i'm not exactly sure why i thought it was confusing but once you get it you're kind of like you know why did i even think that was so hard and hopefully you guys get to that point much faster than i did this is the second part or the continuation of last week's intro to golang functions uh where i covered how to define them how to use them and how to pass and return multiple values from a single function and if functions are new to you and you haven't seen that video i encourage you to watch that because those topics are a prerequisite to this one which is slightly more advanced so i'll talk about functions how to use them as a type then go into anonymous functions and closers and then i'll end with as i said how to pass and return functions from other functions this entire tutorial is going to be coding examples that illustrate these concepts so i'll make sure that i explain everything along the way so you guys can follow me and as always if you find this tutorial to be helpful or informative please do subscribe that feedback and support is very very much appreciated let's go ahead and get started in the last video i gave the definition of a function signature and that refers to the parameters like you see here and the return type of the function so if any function has the same parameters and return type as another they're said to have the same function signature and understanding that is important when it comes to using functions as values and that's really what it means when you hear the term first class functions it means that they can be treated just like any other variable and i'm going to illustrate this by creating a very basic calculator this is going to be a calculator that actually stores the logic for how to execute certain mathematical functions in operations like a real calculator and i'll add functions like you know how to add subtract multiply and divide uh to store in that calculator and so to start off the first thing i'll do is actually define these functions which perform the operations what i've done here is write out four separate functions add subtract multiply and divide which each take in an integer actually taking two integers perform the appropriate operation and then return the value by the way you may have noticed that i have included all the logic for each function on one line and this is completely legal and go i could have just as easily placed the logic on multiple lines which is what you've seen me do in the past but this just saved some space and so i go back to that so i've got the functions of my calculator written out and this particular calculator is going to be one that takes in a set of strings as the expression uh and then basically performs the operations based off of the values of those strings and so what i'm going to do is create a map to map out certain operators to certain functions within the calculator and i'll do that here in the main function here so this is going to be an operation map so i'll call it op map and this is going to hold a map of type string and it is going to map that out to a function with a certain type of uh function signature and so this signature is going to be one that takes in two integers and returns an integer and you may have already noticed that the functions that i defined below have that exact signature they take into integers return one integer so that means that they can exist and be stored as values in this map and so what i'm going to do is map out each operator to the corresponding function and again the reason i'm able to store these functions within this map is because they meet that signature and i'm taking advantage of the fact that we can treat these as first class functions now i've got the logic for my calculator what i want to do is actually create some expressions to pass into this calculator so let's go ahead and create a expressions variable and what i'm going to do this is actually going to be a slice of a slice of strings okay so if you consider a slice of strings to be basically just a list of different strings all separated by commas well a slice of a slice of strings is a list of a list of those types of strings right so it's a list of a list of strings which hopefully isn't too confusing okay so i've written out all of the expressions that i want this calculator to calculate uh so as i say this is a slice of a slice of string so one slice contains all of the necessary logic to perform one operation and i've also refactored the actual op map out into a package level variable instead of one that is defined within the main function and i did that just to make it a little bit more readable and so now that i've got the expressions that i want to actually calculate i'm going to go ahead and implement the logic for the calculator so what we're going to do is just loop through this list of expressions and calculate or perform the calculations of each one one at a time so first i'm going to start out with my for loop and as i said i want to loop through that expression slice and first thing i want to do is check and make sure that the actual length of the expression is the correct length because it's got to have two operands and it's got to have an x y operator so the expression length should actually be equal to three right and if that's not the case then we're going to go ahead and print out an error letting us know that it's an invalid expression invalid expressing if i can spell here looks like i cannot invalid expression uh and then we're just gonna pass in that expression there right and so and if that happens then we'll just go ahead and continue on to the next one so that continue is a key word there once i make sure that the expression is the right length i want to make sure that we can actually perform the operation so we want to check our map and see if that actual if that operator is actually in our map right and we can check if that value is in the map by using this uh ok return value so whenever you actually get the values of a map if you return two values uh the second value that you return will actually be a boolean indicating whether or not uh that value or that key actually exists in the map so for example if i put in app here what i'm doing is first getting the indice of the expression so this first indices so number one is here and that's going to return you know these and then i'm checking to see okay does this key exist in the map if it does it would turn true and then it would turn the value and store it in this op func variable and then i want to add some type of logic here that actually prints out an error statement if that key does not exist in the map so we'll do unsupported operation and if that is the case then we'll go ahead and continue to the next uh operation in the list if the expression of the operation and the operator are both valid then we can go ahead and convert the actual operands into integer values to actually perform the calculation and so i'll go ahead and implement that logic and the logic for this actually will be pulled in from the string conversion packets which is the built-in go lane package and the function to convert a string to an integer is this a to i function and so you pass in the actual string itself oops and that's a zero so i'm going to pass in the string itself and if it cannot be converted into an actual integer then it will return an error as one of the return types and we'll go ahead and print that error out if that is the case so that is the first operand and we'll do the same thing for the second one and if everything checks so if it's the right length it's got the operator both operands can be converted into integers then we go ahead and perform the calculation and how do we know what calculation to perform uh will we have that as a function in our op map and so we're just calling that same function that we return by passing in that key value up here or i shouldn't say calling we shouldn't say you know passing it in i should say calling uh that function and it's going to be p1 p2 which is going to give us our result and we're going to go ahead and print that result out all right so hopefully all that makes sense here there are a few things i need to do here first of all i need to add in this range keyword that i forgot uh also i need to import the string conversion package so let me go ahead and do that so let's go ahead and run this and see what happens alrighty so we can see here that it went through and performed uh the first few operations and then it got to uh the last two which actually was not able to convert these over to integers and this one didn't have enough uh strings in it to perform the operation so we got errors back for those last two so this was just a really basic example showing how you can use functions as values uh storing them you know inside of a map as long as the function meets that function signature requirement one thing i also could have done is actually defined a function type or a new type that has that function signature so let's say i wanted to say op func type and then define that actual signature here so function that takes in two integers return and integer and so now i'm saying that this new type in any variable that meets this function signature can be stored as this type right and so instead of having this here i can now say op font type and this is the same thing so you may be wondering well why would you ever want to do it like this uh it's just best practice that if you're ever going to refer to something multiple times oftentimes it's good to give it a name so this outfunk type i've got multiple signatures that refer to this and so i can say these all meet the op funk type signature another thing that golang allows you to do is define what's called anonymous functions which are pretty much exactly what they sound like they're functions that don't have a name and i'll give you an example of one this here is a really basic example of an anonymous function uh here i just define the function using the func keyword you can see that i actually define it inside of the main function so i don't even give it a name i just say func i notate or include its parameters here uh which is a type integer this one doesn't have a return type and then i just define or declare the function of the body and so this literally just takes in an integer and just prints out a string with that value inside of it and this here is what you use if you need to call the function or if you want to call the function immediately after you define it so i'm doing this within a loop and i'm defining this function and then passing in the value i so this is all looking good here uh so we're going to iterate through this list five times so let's go ahead and run this all right and we can see that we successfully printed uh through each one of those iterations there another use case for anonymous functions is to create closures now closers is kind of a complicated and sometimes difficult to understand topic but a closer is basically a function that references variables from outside of its own body and this function can basically be used to access and assign values to these referenced variables and so it's kind of like the function is bound to those variables and that probably is very confusing so let me just write out some examples here and then i'll go through them okay so here's a really basic example of a closer and while i say basic the truth is that understanding closures can be far from basic they can be sometimes difficult to understand and so i'm going to take this kind of very slowly and step by step so i have created this new function called integer sequence or insect and right off the bat we can see that this function returns another function that returns an integer and so let me say that again this this function insect returns a function that can be called and when it's called that function returns an integer and so right off of that you know that within the body of this statement of this insect function you're going to have to have a return function that returns this that that returns this type this signature here a function that returns an integer and when we get into writing the logic of insect the first thing we do is we initialize a new variable i and set that equal to zero so we've got this variable defined with an insect and then we get into the return statement and as i said we already know where we're returning a function that returns an integer so that's exactly what you see here but this is where we actually define the body of this function that's being returned and this is what is unique about closures within this function all we're doing is incrementing the value of i but this is unique because we're able to access the value of i even though it's defined and declared outside of that function body and so this returned function is all it's all it's doing is incrementing this value by one and then returning that value so that means that this variable only gets initialized to zero when this function is called when insect is called whenever we call the function that is returned from insect it's just incrementing the value and that's what you see up here so insect is called once and we create this next int variable which is really a function that can be called because that's what it returned a function that now has this logic in it but it's unique because it's bound to this variable that was declared within this within the scope of insect so it's kind of like a function with a stored variable a bound variable so each time you call next int which is function that was returned from insect it's just incrementing that variable and so if i run this here we can see that the first time we ran next int it printed out one then it printed out two then it printed out three uh and then when we ran this insect function again it initialized this variable to zero again and then we ran this new ins which is the the variable or the function that got returned from the second call to insect and then you can see the variable is one again so each one of these variables are functions that store their own bound parameters and that's that's the kind of unique feature of closures if you guys are back-end developers are hoping to get into back-end development using go uh closures are something you're going to have to be familiar with because you will see them often when you start to get into writing different api handlers on the back end this discussion on closers has provided us with a nice example of how to return functions from other functions which is one thing i said i would discuss but i also said i would discuss how to pass functions as parameters into other functions so i'll give an example of that before i wrap up so to illustrate a situation where you would pass in a function as a parameter i have decided to use a very popular use case which is the slice function that exists within the sort packets which is a built-in go package and so this slice function can be used to sort a slice of basically a slice of values according to different attributes you can sort it by integers you can sort it by strings alphabetically but you can do that by passing in a couple of parameters one you need to pass in the actual slice itself and then second thing you need to pass and as you can see here is a function that takes in two integers and returns a boolean and this function is kind of like the logic that the slice function is going to use to perform the sorting and so there's a lot of like back-end or you know magic logic behind this and i say magic because that's kind of the term for functions that kind of have a hidden implementation and for the most part goes pretty good at like staying away from that type of stuff but if you want to learn more about the slice function you can look at the go documentation but for the most part all you need to know is that it takes in a slice and it needs to take in the function that as i said describes the logic for how it is going to perform the sorting so i'm going to pass in people which is this anonymous drug that i've defined up top here and if you're not sure about anonymous drugs uh i encourage you to watch my video on structs and that will bring you up to speed on that and then the second part that i need to pass in is a function that as we said takes in two values two integers in this case and then it basically determines how it's going to uh implement that logic by whatever we put here in the body of the function so we're going to put return i'm going to put we're going to sort these these structs here we're going to sort them by age and so we're going to return people i dot h less than people j dot h and again what it does with this logic is kind of hidden but what i'm illustrating here is the fact that slice is a function that takes in another function as a parameter it actually caused this function internally to figure out how to sort the slice that gets passed in and so it's sorting it according to this eights which i've identified here and then what i'm going to do is actually print out this slice and i'll put out a buy age and there we go so if i run this here it says short sort these according and there we have it we can see that it has sorted these by age from lowest to or i'm sorry from youngest to oldest here and we can also do the same thing and by sorting these in alphabetical order so if i wanted to i could just change this to name there and then let me change this string by name and then run this and there we have it in alphabetical order now so if you guys as i said if you want to learn more about this sort function i encourage you to read the documentation but i think this pretty much wraps it up so in this video we've talked about how to define a function as a type we've talked about anonymous functions closers and i've showed you examples on how to pass in and return a function from another function and go and so if you guys have any questions please leave them in the comments as i mentioned before please subscribe and like and i will catch you guys in the next tutorial here on esoteric tech thanks for watching
Info
Channel: Esoteric Tech
Views: 675
Rating: undefined out of 5
Keywords: golang, go functions, go functions syntax, golang introduction, Golang Tutorial, golang functions, Golang For Beginners, go anonymous function, go closures, Golang Programming, Go Tutorial, golang programming language, golang tutorial for beginners, learn golang, golang beginner tutorial, go language introduction, golang tutorials, Golang SDK, Go Installation, programming tutorial, introduction to go, Learn go, golang installation, Go programming tutorial for beginners
Id: soITzMQmycw
Channel Id: undefined
Length: 23min 27sec (1407 seconds)
Published: Tue Mar 30 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.