Learn Go Programming – Golang Tutorial for Beginners

So I wanted to start out with an introductionto the go language itself. Now I know that this is much storied territory, but I haveto start somewhere. And this is going to serve as a stepping off point for us to go througha survey of the entire go language, as well as hitting some of the key libraries alongthe way. So the first thing that we need to know is that go is created by a small teamwithin Google.And that team was made up of Robert griesemer, Rob Pike, and Ken Thompson.Now these guys have been around the software industry for a little while, for example,Ken designed and implemented the first Unix operating system, as well as had a key rolein the development of Unicode. So when these guys got together and decided that they wantedto create a language, we had a lot of talent in the room as soon as these guys got together.But one of the questions that we need to understand is, why create a new language at all? Well,to understand that, we have to look at the languages that are common inside of Google.And that’s the time that go is being designed, there were really three languages that werekey.The first is Python, then Java, and then C and c++. Now, each of these languages inand of itself is very powerful. However, the go designers started to recognize that therewere some limitations that Google was running into, that might not be able to be fixed,given the history and the designs of the existing languages. So for example, when we look atPython, Python is very easy to use, but it’s an interpreted language. And so it can bea little bit difficult to run applications at Google scale that are based on Python,it can certainly happen.But that is one of the challenges that you can run into in verylarge Python implementations. Java is very quick, but its type system has become increasinglycomplex over time. Now, this is a natural trend that a lot of languages go through.They start out very simple, but it has additional use cases and additional features are layeredinto the language, it becomes increasingly more difficult to navigate things C and c++is quick as well. However, it suffers from a complex type system. And additionally, itscompile times are notoriously slow. Now, the type system has been receiving a lot of attentionlately in the C and c++ communities.However, they still have the burden of needing to manageall that legacy code. And so similar to Java, it’s very difficult for them to move pastthe history that they have, because c++ applications written 10 years ago still need to compiletoday. And the slow compile times are another legacy issue that C and c++ have inheritedas well. When C and c++ were designed computers had nowhere near as much memory as they dotoday. So the decision was made to optimize the compilers to use a minimum amount of memory.And one of the compromises that that brought about was the compile times can be a littlebit sluggish. In addition, all three of these languages were created in a time where multithreaded applications were extremely rare. Almost every application that was createdreally had to focus on a single thread at a time.So concurrency patterns built intothese languages are patched in at best. And so working in highly parallel, highly concurrentapplications like Google often runs into can be a little bit challenging when working inthese three languages. So enter go, What does go bring to the party in order to addresssome of these concerns? Well, the first thing that we need to understand is gozi, strongand statically typed language, so it inherits that same feature set from Java and c++. Sowhat do we mean by strong and statically typed with strong typing means that the type ofa variable cannot change over time. So when you declare a variable a to hold an integer,it’s always going to hold an integer, you can’t put a Boolean in it, you can’t put astring in it. And static typing means that all of those variables have to be definedat compile time.Now, are there ways around that? Yes, go does have features that allowyou to get around its type system, but 99% of the time, you’re going to be living ina world that’s strong and statically typed. And getting all the benefits that come withthat. Now, if you come from languages such as Java, then you might be a little concernedthat strong and statically typed languages tend to be a little bit verbose. Well, we’llsee as we get into some go syntax, how there’s been a lot of effort taken to make the compilerdo as much work to understand what you’re talking about with a variable.So you don’thave to explain to the compiler every time what your variable types and things like thatare. In addition, go like a lot of recent languageshas a strong focus on the community that supporting it. Just because go is an excellent languagedoes not guarantee success. Because there are so many languages out there, that it canbecome difficult for a new developer to ramp up in any one.As a result, there’s a strongcommunity built up around go that’s really focused on making sure that the go languagekeeps moving forward, and that new developers have an easier time as possible ramping uponto the language. So what are some of the key features of the language itself? One ofthe first and I would argue most important features that go has is a recognition thatsimplicity is a feature. So as we go through and start learning about the go language,you’re going to run into some features and you’re going to ask yourself, Well, why doesn’tthis exist? Or why don’t we have that feature? And a lot of the reasons Come back to thisfeature.There’s a recognition that if the go language recognizes simplicity is important,then that means that we’re going to have to decide to leave out some other features thatmight be very useful, but would add complexity to the language. Additionally, go focuseson extremely fast compile times a lot of modern development environments to write code fastto build it fast and to test it fast and get feedback back to the developer as quick aspossible. Well, if you’ve got a 45 minute compile time, it breaks that cycle. And developershave a very hard time staying in that design build test loop. And so go focuses on keepingthose compile times down, even though it’s going to yield us fully compiled binariesat the end, go as a garbage collected language, which means that you’re not going to haveto manage your own memory.Now you can manage your own memory. But by and large, the goruntime is going to manage that for you. And the reason for that gets back to this simplicityargument, there is a recognition that a garbage collected language does have challenges whendealing with certain use cases. For example, real time trading systems for stock marketsystems have a very hard time when you’re dealing with garbage collection. However,the advantages on the developer of not having to manage their own memory all the time, weredeemed to be more important. Now, that doesn’t mean that the delays that a garbage collectorincurs haven’t been paid attention to, if you go back through the history of the golanguage, you’ll actually see the past few versions have had a huge emphasis on reducingthe amount of time that the application has to pause during a garbage collection cycle.And at this point, they’re actually really fast, almost to the point that you don’t knowthat a garbage collection happened, in order to address that concern of concurrency godoes have concurrency primitives built right into the language.And we’ll talk about thatas we go through some of these videos. But instead of having a library that we’re goingto have to import, in order to work with concurrency, we’re going to be able to do concurrent developmentright there in the base language. Finally, go compiles down to a standalone library,which means when you compile your go application, everything is going to be bundled into thatsingle binary that’s related to the go application itself. So the go runtime is going to be bundledin there, any libraries that you’re depending on, they’re going to be compiled in there.So you don’t have to worry about reaching out to external libraries and DLLs, and thingslike that in order to make your application work. And what that gives you is version managementat runtime becomes trivial. Because you simply have one binary, you deploy that binary, yourun it, and all of its dependencies are there. Now keep in mind, when I say dependencies,I mean to go dependencies, if you’re going to build a web application that has HTML,resources, and CSS, those have to be bundled along with the binary, but the binary itselfis standalone and self contained.Okay, the next thing that I’d like to do is show yousome of the resources that are available to you, as you start to explore the go language. One of the most useful resources that you’regoing to be able to take advantage of as you’re ramping up on go, is goes website here@golang.org.Now, why is it go lang.org? Well, if you take a minute to think about a language calledgo, that doesn’t really lend itself to unique search results in Google or Bing.So go lang.orgit is, as a matter of fact, a lot of places that you see go mentioned, you’re gonna seeit actually described as go Lang, because that makes it a little bit more unique whenyou’re looking for search results. So the first thing that you might notice, as we gointo the homepage here is this isn’t really laid out like a lot of traditional home pages.This, in my opinion, is very much an engineering homepage. So instead of a lot of design aesthetic,this gets right into the engineering aspects and shows you how to start working with thelanguage.So this yellow box over here is going to be your entry point for your firstgo application. So if we go ahead and click this run button, you see that we almost instantlyget an application sent back to the server, it gets compiled, and it gets run for us.So we can start playing around with go code without installing anything on our local machines.And we’re actually going to take advantage of that through this first few videos. Asa matter of fact, if I make a small change here, so maybe if I will say, Hello, YouTubepeoples and run that again, then I’m saying hello to y’all, so Hi. So it’s as simple asthat in order to get started with the go program. Beside that window, we see this download GObutton.And that’s going to take you to resources that you’re going to be able to use in orderto download the latest go binaries, as well as download older versions of the runtime.And if there’s an unpublished version, for example, at the time I’m recording this go1.8 is at RC two, you can go ahead and download that install that and check that for bugsand play around with new features in the language.If we come across at the top, we see thisdocuments link here. And this is going to be another critical resource as you’re startingout with the language. As a matter of fact, you’re going to refer back to this page quiteoften. But if you really want to walk through on the website, a tour of the go languages,and I would recommend you go to this Getting Started link.This is going to get you starteddownloading and installing the go compilers and tools and things like that. And you cansee as we navigate there, it’s going to show you the different architectures that you’regoing to be able to use with go and there’s quite a few and how to get started on eachone of those. If we keep continuing down the tour of go is kind of an introduction to thego language that takes you through a gradual introduction.So it’s going to start out withsome very simple Apple And then build up more and more and more and help you understandwhat’s going on with go concurrency and things like that. Effective go is a very useful article,especially as you start to mature in your understanding of the language, and reallyunderstand how the go language is used. So I would encourage you to go into that it’sa pretty lengthy read. But you should consider this requiredreading if you’re actually going to start building non trivial go applications. Butwe’re not going to worry about that right now. We got plenty ways to go before we needto get through all of this stuff. And then down here at the bottom is some referenceinformation. This is more advanced documentation that you’re probably not going to need rightaway. But for example, the command documentation gives you a lot of information about the gotool itself that you’re going to use for local development with go, there’s a lot of thingsthat the go program does.And this is going to help you understand how to navigate that.The packages link is perhaps where I spend the most time on gos website. And this givesyou documentation for all of the libraries that are built into go. So when you installgo and you install the go binaries and tools, you’re going to get all of these librariesavailable to you. So just scanning down, you can see that we’ve got different librariesthat are targeted at working with archives, we’ve got some cryptography libraries, databasedrivers, continuing to go down, we’ve got some things for working with HTML, and networktraffic. Now, some things that you might find missing here are we don’t have any GUI libraries.That’s because at this point go really isn’t focused on the use case of client applicationdevelopment.So go is really targeted at building servers and web applications. And so that’swhere a lot of the libraries are going to be focused on. There are some projects thatare working on mobile applications using go as well as client side applications usinggo but they’re not officially supported at this point. If we come over to the projectlink, we’re going to find some information about history of the project, what releaseshave come out and when, as well as some links to mailing lists and resources that you cantake advantage of. If you want to keep track of the development of go as a language aswell as if you find an issue in the go language, you can see some information here on how toreport that issue. And then we’ve got the Help link here.And this is going to be oneof your more important links as you get started here because this is going to be your on rampinto the community. Now the two most active in my experience are the go forum, which isa nice discussion forum that allows you to post your questions and get people to answerback. But if you want something a little bit more real time then the gopher slack is aSlack channel specifically targeted at NGO development. And there’s multiple sub channelsin there for new developers for library developers. Even a lot of the NGO meetup groups have theirown sub channels on the gopher slack. So if you want to get on the gopher slack that Iwould encourage you to come over here to another website called go Lang bridge. And this iswhat I consider the on ramp to the NGO community. Because NGO Lang bridge is specifically thereto advocate for the go language, and to make sure that the community is healthy and strong.As I said, one of the key aspects of the go language is a focus on having an excellentcommunity.And really, it’s go Lang bridge and the awesome people that support it, thatare making that happen. So if you scroll down a little bit, you can see some links to theonline communities. If you want to join the Slack channel, you do have to receive an invite.So this link here is going to take you to the forum that’s going to allow you to getthat invitation. And there’s no problem getting the invitation, the only thing that they askedyou is to read the community guidelines, there is a code of conduct that just make sure thateverybody is going to be treated respectfully in the community, just to make sure that we’reall here trying to help each other out. And the last thing that I want to show you onthe website is this play link here.Now this link just flies out an editor. And this isreally nice, because this is available throughout the site. So if I come to the packages, andlet’s just say I dive into the network package, and I’m learning about some network function,then I can go ahead and pop into the play, I can create a real quick proof of conceptgo application in order to make sure that I understand how that’s working. And again,just like we saw on that homepage, if I click run that I can go ahead and execute that.Now there are some limitations, obviously, this application is sent to the back end.And there are some limitations, you’re not gonna be able to read the file system at theback end, for example.But a lot of the things that you want to playaround with, you can play around with in this online environment. Now another place to getat this playground is over here at play that golang.org. And this is the last thing I wantto show you in this introductory video. So this is going to be the environment that we’regoing to focus on. And actually, let me make that a little bit bigger. So maybe it’s alittle easier for you to see. But this is going to be the environment that we’re goingto focus on as we start to learn the go language. So we’re going to learn the basics of go applicationhere, we’re going to start playing around with how we’re going to work with variablesand logic and looping and things like that.Now, eventually, we’ll get to installing alocal environment. And you can certainly take advantage of the other resources on go Langwebsite, if you want to get there before I create a video on it. But I think that there’sa lot that we can talk about without making a commitment to setting up a local developmentenvironment by just going through this playground here. So if we take a second look at thisapplication, we see some of the key aspects of any go program. And the first thing thatyou see at the top is this statement package main. Every go application is structured intopackages. So every go file that you’re going to have is going to have to declare what packageit’s a part of nain is a special package, because main is going to be the entry pointof any one of your applications.Down below that we have an import statement. And thisis the statement that we’re going to use in order to import additional libraries. So thislibrary is called thumped, which Yeah, you actually say that in the NGO community, Ican’t bring myself to say that. So if I call that FMT, I hope that you’ll forgive me. Butin the NGO community, you will often hear this called thumped. And this is the packageis going to allow us to format strings. So you see down below here and our main function,which is the entry point of our application, so the main function in the main package isalways going to be our application entry point. And this is going to be where we’re goingto contain our first code that’s going to run in go. So we’re going to call into theFMT library.And we’re going to pull out its print ln function, and that print ln functiontakes one argument, and that argument in this case is a string. So we’re going to printout Hello playground. Now if I go ahead and run this, then down below at the bottom ofthe screen, here, you see Hello, playground gets printed out. And then it says programexited. If we have an error in the application, say if I delete this quotation mark and run,then you’re going to get a compiler error printed out at the bottom, that’s going tohelp you debug your application. So this online environments going to be very good for youto get started, because it’s going to help you through understanding what’s going on.So for example, we see here in line eight, it got an unexpected semi colon or new line,when instead it was expecting a comma or a parenthesis. And the reason for that is becausethis closing parenthesis actually became part of the string. So the line terminated early,and it didn’t have an end to the function call.So if we go ahead and re add the quotationmark, and run, we’re good to go. And we’ve got our first start in a go application. SoI hope that this was helpful for you a little bit of background in a language that you’regoing to be learning I always find is a little bit valuable, it helps to understand the motivationsfor the creation of the language and the major features, in order to understand what problemsthat language is going to try and solve and how it’s going to go about trying to solvethem. What I want to show you is how to get started setting up your own local developmentenvironment to program with go. Now I know in the last video, I showed you this websitehere, and I said that this is what I want to use. That is the website it played@golang.org.And I said that this is the website that I want to use in order to show you a lot ofconcepts that you’re going to need to be familiar with with the go language.And that’s stillmy plan. But as I thought about it, I decided that it doesn’t really make sense to forceyou to use the playground, just because it’s a really good place for me to demonstrateconcepts. So I want you to have all the tools available to you to set up your own localNGO development environment. So you can play around with creating your own applicationsas you learn about this wonderful language. So the first thing that we’re going to needto do is we’re going to need to download and install the go language in the go tools itself.And so in order to get started with that, we’re going to start over here@golang.org.And we’re going to click on this download go link here. Now this link is going to take you to allsorts of different versions of go.But in general, if you’re getting started, just pickthe latest stable version that’s available for you, and it’s not going to steer you wrong.Now, if you’re a Windows user, then I would encourage you to click this MSI link, it’sgoing to download an installer and go is going to be put on your system automatically. However,if you’re using os 10, or Linux, then I would recommend that you go to this installationinstructions link here and follow the instructions here. Now, you’re still going to need to downloadthe go binaries. But if you scroll down just a little bit, you’re going to see this commandhere. And this is going to give you the tar command that you’re going to need to use inorder to unpack the go binary and install it onto your system. So I’ve already donethat. And I can show you that by opening up a terminal here.And the default locationto put go is in the user directory underneath local and then in a folder called go. So ifwe look at there, and they look at the contents there, I see that I have all the go toolsinstalled. So with the Windows Installer, all it’s going to do is it’s going to placethese into C colon backslash go. And I would strongly encourage you if you can accept thesedefault locations that you go ahead and do that because it’s going to make setting upyour environment just a little bit simpler. Now after we get go installed, we have a littlebit of configuration in our environment in order to be able to use go effectively. SoI’m going to come back to my home directory here. And I’m going to make a change to mybash RC file. Now I’m on Ubuntu. So it’s going to be in my bash RC file. If you’re an LS10, it’s going to be your bash profile. If you’re in Windows, basically what we’re doingis we’re setting environment variables.So if I open that up and come down to the bottom,then I see that I’ve got the pre generated bash script. I’m not going to really worryabout that. But there’s a couple of variables that we’re going to need to set. Hello, everybody,I need to pause the video here for a second and make an important announcement. So assoon as I originally released this video, Dave cainy came in within a couple of minutesand he expressed a concern about one of the things that I’m about to talk about.Now I’mabout to talk about setting a couple of environment variables here and showing you how they work.Now one of those variables is called go route. And setting go route has been shown to causeproblems as you move through different versions. Go, especially if you’ve got multiple versionsof the language on your system. So if you want more information about that Dave hasa really good blog post here that you can go to to learn more information about it.But for now, please keep in mind, if you’re able to install go at its default locations,which on Unix or Mac is going to be slash user slash local slash go in on Windows isgoing to be C colon, backslash go. If you’re able to do that, please do that. And thengo ahead and avoid setting go route. Now you will need to set the PATH variable to go rootsbin directory in order to access the go executable.And you will need to set go path which we’regoing to talk about after that. But if you can avoid setting the go route environmentvariable, it’s going to save you a lot of heartache. So well, I’m going to show youhow to do that in case you do need to set it please avoid that if at all possible. Okay,at this point, I’m going to resume the video and continue talking about the environmentsetup. Now the first variable that you’re going to need to know about is called go route.Now, if you’ve installed go to its default location, you’re not going to need to worryabout this.But if you’ve decided to install go somewhere else, for example, maybe you’veinstalled it in your home directory, then you can go ahead and set go route. And that’lltell the environment where to go to find the go binaries. Now the next thing that we wantto do is we actually want to set a PATH variable to the go binaries themselves. So I’m goingto go ahead and export a PATH variable. And that’ll Of course, start with my existingpath. And then I’m going to add on to that go route. And then I’m going to whack on thepath slash bin. So there’s quite a few binaries that we’re going to be using on a regularbasis. And those are in go route slash bin, so you’re going to want to make sure thatthat’s part of your path.Now once I do that, let me go ahead and save this. And then Iwill use the source command in order to get my shell to reread the bash RC file. And thenI should be able to test to make sure it goes available by typing go and version. And youcan see here I’m running go version 1.8 release candidate three. Okay, now there’s one more thing that we needto do in order to get our environment fully set up. And I’m going to go back into my bashRC file in order to do that. And that is the setting of a second environment variable.So we have go route. And that’s going to tell the environment where goes installed. Butwe’re also going to be downloading a lot of packages as we work with go, because we’regoing to be taking advantage of libraries that other people have published in orderto build our own applications out. So those applications as well as our own source codeare not going to be located with the go binaries, they’re going to be located in a path thatwe’re going to specify with a another variable called go path.Now go path is either oneof the most awesome or one of the most horrible things about go because it gives you thisreally nice way to specify where you go projects are located. However, it does kind of pushyou towards having this monolithic repository of all these binaries and your applicationstied together. So I’ll show you a little bit of a hint on how to work with that. But fornow, let’s go ahead and set a go PATH variable in my home directory. And then I will callthis go lib. Now just like with go route, we might have some executable binaries thatare going to be stored in our gopath. So I’m going to go ahead and export on our path again.And we’ll start with our existing path. And then I want to add on go path slash bin. Thatway if we install any libraries that have executables, and we will be installing librariesthat have executables, then we’re going to be able to track that.Now just to show youreal quick what that’s going to do. Let me go ahead and save this out resource, my bashRC file. And then I’ve actually already created this folder here called go live. Now if Igo into go lib, and I look at the contents of that it’s currently empty. But I can changethat by using a tool called go get. So if I get a library that’s at github.com slashNSF slash go code. This is historically the library that people use to provide autocompletefunctionality in their go applications. So if I go ahead and hit Enter, and wait a second,then go back into my go lib folder. And look, now I’ve got some content here. So if I lookin the bin directory, I’ve got this go code executable. And if I come back to the sourcedirectory, then I see that I’ve got this GitHub comm folder.And inside of that is NSF. Andinside of that is go code. So if I come in here, here’s all of the source code for thego code library. So when I’m working with go code, it actually downloads the sourcecode and compiles it into the go code library for me. And that’s what that go path is goingto do for you. The problem that you might run into is that this use of gopath tendsto drive towards monolithic repository. So you’re going to have go code, you’re goingto have your own code, you’re going to have all sorts of other libraries, all put intothis one location.Now when I create my courses, that creates a lot of visual clutter. Andso that isn’t exactly the form of gopath that I use. What I do is coming back into my bashRC file is I actually use a capability of gopath to create a compound gopath. So insteadof a single path here, I’m actually going to re export go path and I’m going to addon an additional path to this and I’m going to add Home mic and code. Now a lot of timeswhen I’m teaching courses, I only need to go pants. And so I’ve got go live. And that’sgoing to be where all my third party libraries go.And then I’m going to have another folder,that’s going to be what’s called by workspace location. So let’s go ahead and write thisout. We’ll source this again. And now I’ve got the full gopath. So if I come into myNGO lib, and I remove everything from it, now it’s empty again. So if I go ahead andgo get that repository, again@github.com slash NSF slash go code. And now you see that itactually goes into my go lib folder.If I come into my code folder, which I also createdearlier, that’s still empty. So the first segment of your go path is going to be usedby go get in order to store your files, but all of the segments of your go path are goingto be searched for source code. So that’s going to really help us as we’re setting upour workspace. So speaking of which, that’s the next thing that I want to do. So a workspacein go isn’t anything special, the only thing that you need in order to create a workspaceis to have a single directory called SRC in it. So if I add a directory called SRC intomy code folder, then I’ve got to go workspace. Now SRC, as you might expect, is where you’regoing to keep your source code. So when I set go path to slash home slash Mike slashcode, it’s going to look for an SRC directory in order to find my source code.Now, thereare two other directories that you might find in a workspace that are interesting. And wefound one already when we installed that go code library. And that’s been. So anytimewe’re working with a project and a binary is created, it’s going to be put into thatbin directory. And that’s also why we added that bin segment to our path, the last directory that you might find inyour workspace is a pkg directory. So for compiling something, and it’s going to generatean intermediate binary, which means it’s not going to be a fully compiled application,it’s going to be an intermediate step.So for example, if we’re taking a third partylibrary, and we’re integrating that into our application, then the pkg directory is wherethose intermediate binaries are going to be stored. And the reason those are created isso that they don’t have to be recompiled every time. So when you compile your go application,go is going to check to see if any of the source files in that directory have changedsince the last time it compiled them. If it hasn’t, then it’s not going to recompile thatpackage, it’s just going to go ahead and link them into the binary that it’s creating foryou. Okay, so let’s go ahead and clear this out. Because that’s getting a little bit cluttered.And now let’s set up an editor to work with go code. Now, there’s a lot of editors thatare out there. And so what I’m going to show you is just one, but feel free to explorethe option for your favorite editor, because there’s probably a go plugin for it.And allof these plugins are really good right now. So I’m going to show you the one that I’vebeen using lately, which is Visual Studio code, now might be a little bit surprisingMicrosoft, oh my goodness, they’re doing all this really awesome stuff for the open sourcecommunity. But it’s really true, one of the best development experiences that you’re likelyto come across with go is in this Microsoft product running on Linux. So I’ve already installedit. But if you do need to install it, you can come here to code Visual Studio Comm. It’s going to give you the binaries. In thiscase, I’m running Ubuntu. So I would download this.db file and install that onto my system.And then I’m going to be able to run that by simply typing code in my application launcher,or I’ve already set up a shortcut over here in my taskbar.So as soon as I run that, I’mgoing to be presented with this. Now you can see I’ve already opened up a folder here,you can open up a folder to your workspace by simply file open, and then pick your folderthat you want to be working with. So we’re going to be working with code. But there isone setup step that I need to go through before Visual Studio code is quite ready to go.Andthat is I need to install the plugin that’s going to allow us to work with go code. Andso if I click this button down here called extensions, then I have a list of all sortsof extensions that I can add in for Visual Studio code. Now, right here is the go extensionby Lu COVID. Now there’s a couple of go extensions, but I would strongly recommend you use thisone here by Luke, because it is really amazing. It offers a lot of capability, it really makesVisual Studio Code of first class environment for developing go, okay, and as fast as thatthat’s been installed. And it was that fast, because it’s been cashed from earlier. Andthen I’m all set and ready to build my first go application.So let me go ahead into thissource directory. And I’m going to create a folder that’s going to contain my sourcecode. Now your first temptation might be to just plug in your source code right here inyour src folder. But I wouldn’t recommend that the standard structure that you’re goingto use in a go application is to mirror where your application is going to be in sourcecontrol. And that makes it go gettable. So in this case, if I was going to keep thisfile on GitHub, I would create a folder called github.com.And then underneath that, my GitHubaccount is vi n si Mk II don’t ask long story about why I called it that. And then I wouldhave an application name. So I would call this maybe first app, and that’s the folderthat I’m going to store my application in. And the reason for that is if you think aboutif I check this into GitHub, and observatory called first app, when I go get that, it’sgoing to recreate this structure.And so you want to create your applications followingthat structure. So now I’m ready to create my first file, and I will call that main go.And then I can start adding in my source code. So the first thing that I’m going to add ispackage main. And then when I save this, oh, it looks like I expected something to happenhere. And it’s not happening. I think it’s because yeah, he told me that I needed toreload the environment. Good. So I’m going to go ahead and do that. So I’m going to exitout of Visual Studio code, and it should kick right back off, but it has to initialize theplugin. So now I see what I was expecting to see. And that is that the NGO plugin hasrecognized that they don’t have all the tools that it needs in order to provide me all thesupport that it can, because the NGO plugin for Visual Studio code is actually like alot of the plugins and other languages, it takes advantage of these language services,for example, it’s talking to me about go land, go lint isn’t available on my system.Andso it’s not going to be able to provide linting capabilities. So basically, the go plugin,cause up to all these language services. The nice thing about that is if you decide toflip between different editors, your experience is pretty much the same, because they’re allrelying on the same language services in order to provide you the capabilities that you have something go ahead and install all. And youcan see there’s a pretty long list of libraries that it’s installing for me. Okay,and now they’re all installed. So that took about a minute to install all those dependencies.So I expect that you’d probably have a similar experience in your own environment. Now, beforewe start adding anything else, I actually put some quotation marks around this package,that’s not going to be correct.And now I’m ready to start actually building out my program.So let me go ahead and put in an import statement here. And we haven’t talked too much aboutimports. But we have mentioned a little bit about packages, packages, or how code is organizedinto sub libraries inside of NGO. So for example, if I want to build a web application, thenI might pull in the net HTTP package that you see here, in order to set up my web requesthandlers. But for now, I just want to do a simple Hello, go example. And so I’m justgoing to import the FMT package. But you notice that the NGO plugin for Visual Studio Codegives me autocomplete, so any library that’s available on my go path is going to be foundhere. So now I’m going to create a simple function called main.And inside of that,I’m going to access the FMT package. And notice that I get autocomplete functionality here.So I can go ahead and say I want to call the print ln function, and it gives me the signaturefor that function. So I can go ahead and add that in here. And the I just want to say hello,go. Okay, so in order to run this, inside of Visual Studio code, you do have the abilityby pressing Ctrl backtick, you can open up a terminal right here inside of the editor.And there’s a couple of different options that I have in order to run my application.So the first thing that I can do is I can use gos run command, as you see here, andI can give the path all the way through to my source code.So if I come and I just keeptapping through, then I’m going to get source slash github.com, slash vianne, si MKE slashfirst app slash main.go. So if I run that, then it will compile that temporarily, andrun that for me. And it also compile in any third party libraries. So the FMT packagewas compiled in as well. Now, that’s a really good way to get a really quick run. Anotherway that you have available to you is to use go build and go build takes the actual packagepath. So all we’re going to do here, is compile the first app package.Now, if it finds amain package with a main function, then it’s going to compile that as an executable, likeyou see right here in my home directory. So I can go ahead and run that. Now the lastbuild tool that I have available is go install, go install is actually expecting to be pointedto a package that has an entry point. And it’s going to install that into your bin folder.So let’s go ahead and see that work.So we’ll go to github.com, my username for GitHub,and then first app again. So notice I’m using the package address, I’m not using the folderpath. If I run that, notice, I don’t get anything in my main directory. But if I come into thisbin folder here, now I’ve got first app over here. So if I come back to my terminal, binslash first app, run that I get Hello, go printed out again. Okay, so the last thingthat I want to show you if I come back over to the terminal, so you see how we have allthe packages that we’re working with locally over here in this code directory. If I cometo the first element of my go path, which is go lib, and look at that, you’ll see thatthis is starting to become a pretty busy place here.Because now I’ve got three source folders.And if I come into GitHub comm, you’ll see that I’ve got quite a few packages. So nowall of these third party dependencies aren’t cluttering up my main workspace. They’re allin this go lib folder, and then I can focus on my development in my code folder. Now thelast place that you’re going to see packages is over in the NGO installation directory.So if I look in that folder, you see here that I have this directory called source.So the ghost source code itself is in fact a valid go workspace.So if I come in herelook If the folders in here, you see, these are exactly the go standard library. So here’sFMT. Here. You see if I scroll down a little bit the net package, if I go into the netpackage, you’ll see that that contains the HTTP package. If I come into the HTTP package,and list those contents, you see all of the source codes for all of the modules that youcan see over here at go.Lang Comm. So if I follow that through, over here, scroll downto net, and HTTP, you see all of the capabilities that are available in here? Well, all of thoseare provided by this source code here. So if you have any questions about how any oneof those libraries work, or how something’s configured, you can jump right into the sourcecode and see how it’s all put together. Over the last couple of videos, we’ve laid somefoundation by talking about the history and the features of go and working through settingup the local development environment.What today is the day that we’re going to starta discussion about the go language itself by discussing how to work with variables.So in order to fully cover how to work with variables, there’s several topics that we’regoing to need to cover. We’re going to start by learning how to declare variables. Thenwe’ll move into a discussion about how go considers read declaration variables. Andthis concept of shadowing. After that, we’ll talk about visibility, where we’re going to learn how we can control what aspects ofour program can see a variable that we create, then we’ll talk about naming conventions.And finally, we’ll wrap up with a brief discussion about how to convert variables from one typeto another. Okay, so let’s go ahead and get started. So I’m going to be using the playgroundin order to host our conversation. That way, you can follow along whether you’ve set upa local development environment, or just want to follow along online.So as you can see,when we first load up the playground, we’ve got this one statement program, which is justprinting out the string hello playground to the bottom of the screen, when I click thisrun button here. Now this statement can only ever do one thing because we’re passing ina string literal. And similarly, if I pass in the number, say 42, and run it, then weprint 42 out. Now no matter what we send to this print ln function, it’s only going toever do that one thing. So in order to provide a little bit more flexibility to our application,we’re going to introduce variables.So there’s actually three different ways to declare variablesand go and we’re going to go through each one of those. And then we’ll talk a littlebit about where you might use each format. So the first thing that we can do is actuallydeclare the variable itself. And that’ll be done using this kind of a statement. So we’regoing to start with the var keyword, then we’re going to have the name of the variableand the type of the variable. Now if you come from another strongly typed language, thismight look a little bit backwards, because you might be expecting to see something likeint i. Well, that’s not actually how go works. And if you think about it, the way gos structures,things actually looks more like how you read it. So I’m going to declare a variable calledI that’s going to be of type integer. So the way you declare variables and go, it’s prettymuch the same way that you speak. And so it might look a little bit odd when you firststart working with it.But it very quickly becomes intuitive. Now that we have our variabledeclared, we can go ahead and assign a value to it. And we’ll do that simply with the equalsoperator. So once we have that set, we can go ahead and replace this with an AI, runit and we print the value 42 out. And since variables in go can vary, we can go aheadand change the value of that to say 27. When we run again, we get the value 27 printedout. So now even though the statement can only ever do one thing at a time, the programthat runs up above this FORMAT statement can actually influence the value that’s printedout to the console. Okay, so let’s go ahead and get rid of this, and then explore anotherway to initialize this variable. Because one of the things that we trying to do and gois we want to keep things simple. So if we need multiple lines, then we’ll go ahead anddo that. But we don’t want anything to be more verbose than we have to.So we can actuallycombine these two lines in one like this. So we can initialize the variable i as aninteger and assign the value 42 in the same line. So if we go ahead and run this, thenno big surprise, we get the value 42 printed out. Now, this is actually still making uswork a little bit harder than we need to. Because since we’re assigning the value 42to this, the go compiler can actually figure out what data type it needs to have. So wecan go ahead and tell it to figure this out for us by replacing all this text with thistext here. So if we just say I and then use this colon equal operator and the value 42,and run this, then we get this really nice concise way of setting things up. Now, whereare you going to need each one of these? Well, let me go ahead and add them back in so wecan talk about them. So we’ll set var I integer i equals 42. And then we’ll use var j integerequals 27. And then we’ll set up K and that’s going to be equal to 99.So we have these three different formats.So when are you gonna want to use each one of these? Well, the nice thing about thisfirst format is there are going to be times when you want to declare a variable but you’renot ready to initialize it yet. So for example, if you want to declare variable in the scopeof this main function, and then you have a loop or something like that, that sets upa local variable scope.And that’s where the variable is actually going to be assigned,then you can go ahead and use this first syntax. The second syntax is valuable, if go doesn’thave enough information to actually assign the type that you really want assign to it.So to show that, let me go ahead and add another print statement here. And I’m going to needto come up these other lines out in order to make things happy for us. So let me goahead and change this print ln to a print F. And what this is going to do is it’s goingto allow us to provide a formatting string and print things out that way.So we’ll printout the value, and then I’ll print out the type of the variable, and then I’ll pass inj twice. And so if I run this, then we get the value 27. And no big surprise, it’s aninteger. But what if we want this to be, for example, a floating point number? Well, withthis syntax, it’s as simple as just changing this to float 32.When we run this, then gounderstand that we want to use 27 as a floating point number. Now, if we tried that with K,down here, so let me uncomment the K, switch this over to use K and run, then you see thatthe number 99 is inferred to be of type integer. And we can influence that a little bit byadding a decimal point.And that’s going to give a hint, making that a float 64. But there’sno way to use this colon equals syntax to initialize a float 32. For example, go iseither going to decide it’s an integer type, or it’s a float 64 type. So if you need alittle bit more control than the second declaration, syntax is going to be valuable for you. Nowthe next thing that I want to show you is how we can declare variables. Now we’ve beendeclaring variables one at a time and inside of a function. Well, another way that youcan declare variables is up here at the package level. Now when you’re doing it at the packagelevel, you cannot use this colon equals syntax, you actually have to use the full declarationsyntax. So we can declare a variable is an integer set equal to 42. So that works, comedown, wipe out this code, and then replace this with I. And you see that we have thevalue 42. And it’s of type integer. So just like we have before, we can go ahead and tellit to declare that as a float 32. And the compiler recognizes, well, I can make 42 afloating point number, that’s not going to be a problem at all.Now, of course, if youtry something like this, the compiler has no idea how to convert the string food toa floating point number, and so it’s going to fail on you. Another thing that we cando at the package level is we can actually create a block of variables that are declaredtogether. And to show you why that’s valuable. Let me just drop in some variables that wecan play around with.Okay, so as you can see, I’ve got a little bit of Doctor Who hasa brain here, and say I’m writing a program that’s going to print out some informationabout the doctor’s companions. So here we got a variable actor name, that’s going tobe Elisabeth Sladen, then we got her companion name, which doctor she worked with, and whatseason she was on. So by declaring these variables like this, things are actually a little bitcluttered. Because again, we want things in go to be as clear and concise as possible.So all these var keywords are actually cluttering things up a little bit. So what we can doinstead of this is actually wrap this whole section with a VAR block. And then we canactually get rid of the use of this var keyword. And now all of these variables are going tobe declared because they’re inside of this var block. And we can actually show that they’rerelated somehow. Now they don’t have to be related. That’s a design decision.But wecan do that. So if we had another set of variables that were related to a different context.So say, for example, we had a counter, and that was going to be an integer initializedto zero, then we can have multiple variable blocks at the package level. And that’s justgoing to allow you to organize your application a little better, and keep your code a littlebit cleaner. Now the next thing that I want to show you and let me just drop in some codehere is how variables work when you’re trying to read Eclair them.So you can see in this application, we’redeclaring the variable i up here in the package scope, then I’m declaring it here inside ofthe main function, and then I’m re declaring it here on line 11. Now, if I try and runthis, I’m actually going to get an error. And the error comes on line 11 here, becausethere’s no new variables here. So I can reassign the value of i 13. But I can’t declare a newvariable here. And that’s because the variables already declared on line 10. And you can’tdeclare the variable twice in the same scope. However, if I get rid of this line, noticethat the application runs just fine, and uses the value 42. So even though I is declaredtwice in my application, once at the package level, and once inside of the main function,that’s okay. And what happens is that the variable with the innermost scope actuallytakes precedence.So this is called shadowing. So the package level is still available, but it’s being hidden by the declaration inthe main function. And I can actually show that by copying this line up here and running this. And now you see I get 27,which is the package level scope. Then I create the shadow Variable setting equal to 42. Andwhen I print out I again, then I get the new value of i.Now another interesting thingabout variables in go is that they always have to be used. So let me just drop in thisexample here. And let’s walk through it. So I’m declaring a variable, I’m setting it equalto 42, then I’m instantiating, a variable j, setting it equal to 13. But I’m only usingi. So what happens when I run this? Well, if I do, I actually get yelled at, becausej is declared and not used. And this is one of the things that’s going to keep your goapplications nice and clean. If you have a local variable that’s declared and not used,then that’s actually a compile time error. And the reason that’s really valuable is asyour application grows and evolves, and new features are added and old features are deprecated,you’re very likely to end up with some old code hanging around inside of your functions.Well, if any of your old code or variables and those variables are no longer used, thenthe compiler is going to detect that for you see that you can make sure that you can cleanthose out.Now another important thing to know about when you’re working with variablesis how to name them. And there’s actually two sets of rules that you’re going to needto keep track of. One is how naming controls visibility of the variable and go. And theother is the naming conventions themselves. So notice that I’ve been creating lowercasevariables. Well, that actually isn’t always the case in NGO, because if I’m declaringa variable, and let’s just declare it at the package level, and I declared as an integer,with the name I, and I go ahead and work with that, then that lowercase variable name actuallymeans that this variable is scoped to this package.Now, this is a main package. Andso this doesn’t really matter so much. But when we get into working with packages, thisbecomes extremely important. So lowercase variables are scoped to the package, whichmeans anything that consumes the package, can’t see it and can’t work with it. But ifI switch to an uppercase letter, then that’s what’s going to trigger the go compiler toexpose this variable to the outside world.So it’s a very simple naming convention. Andthere’s really only three levels of visibility for variables in go. If you have it at thepackage level, and as lowercase is scoped to the package, so any file in the same packagecan access that variable. If it’s uppercase at the package level, then it’s export atthe front of package and it’s globally visible. And the third scope is block scope. So whenwe have this main function here, it’s actually establishing a block scope. So when we declarethis variable I write here on line 10, that variable is scoped to the block. And so that’snever visible outside of the block itself. Now beyond that, it’s important to understandthe naming conventions in go, and there’s a couple rules that we need to follow. Thefirst is that the length of the variable name should reflect the life of the variable. Sofor example, in this example, we’re declaring a variable i, and we’re using it right away.So having a very simple variable name is perfectly acceptable.And this is going to be especiallytrue if you’re declaring counters and for loops and things like that, it’s very commonhave single letter or very, very concise variable names, because the lifespan of that variableis very small. And the amount of time that you have to keep the meaning of that variablein your head is very small as well. However, if you’re declaring a variable that you usefor a very long time, then it’s best practice to use a longer name. So for example, if thiswas going to represent the season number that our companion was on, so say, season 11. Andwe use that throughout this entire main function, then we’d want to use a name something likeseason number. Now, if you’re working with a package level variable, and that packagelevel variable is going to be used in quite a few other places, then that’s where you’regoing to want to use the most verbose variable name.Now, you still shouldn’t get crazy,you shouldn’t have 50 character long variable names if you can avoid it. So keep your namesas short as you can. But make sure that the names of those exported or package level variablesare clear enough so that somebody who’s outside of that source file understands the meaningof it. The other thing I’d like to talk about is how to work with acronyms, because in otherlanguages, you might see variables like the URL, and then maybe this is http google.com. You might see a variables name like this.Well, the best practice and go is actually to keep these acronyms as all uppercase. Soif you’re working with a variable called the URL, the URL should be all uppercase. Similarly,HTTP and any variables like that.So anytime you see an acronym, make sure that that’sall uppercase. And the reason is for readability, it’s very clear, we’re used to seeing URLand HTTP all put together. So when you read this variable, it’s very clear that you’retalking about an HTTP. Maybe you’re talking about an HTTP request that reads a littlebit cleaner than if you go ahead and make those lowercase. So just some rules to keepin mind as you’re creating variables. Now the next example that I want to show you ishow we can actually convert from one variable type to another. So notice that I have twovariables here. I’ve got variable i on line eight, and then I’m declaring as an integerwith the value 42. And then I’ve got this variable j, that’s going to be a floatingpoint number. Now what I want to do is I want to actually treat it as a floating point numberand assign that value to J.So the way that I do that is using this conversion operator.So if you look on line 12, it looks like float is being used as a function. And in fact,it is. And this is a conversion function. So when I run this program, you see that thefirst print statement on line nine, prints 42, as an integer, the second print statementstill prints the same value 42. But now it’s been coerced into being a floating point number,they have to be a little careful with this. Because if you go the other way, so for example,if we go from a float 32 to an integer, and then I convert that and run it, it looks likeeverything’s okay.But keep in mind, a floating point number can have a decimal on it. Sonow I’ve actually lost information to the conversion. So the important thing about thisis I have to explicitly convert, because if I just tried to do this, then I’m actuallygoing to get a compile time error, because go is not going to risk the possibility oflosing information through that conversion. So you have to do an explicit conversion,when you’re changing types. That way, it’s your responsibility to understand if you’relosing information or not. Now, the other thing that’s important to know is if I decideto work with strings, it’s a very common use case, to try and convert an integer into astring, say, for example, you want to print it out to a log file.Well, if I run this,I get a pretty odd result. The first line prints out Okay, 42. And that’s an integer,that’s okay. But then I get an asterisk. That’s of type string, what the heck happened there?Well, in order to understand that, you have to understand how strings work with go, astring is just an alias for a stream of bytes. So what happens when we asked the applicationto convert the number 42 into a string is it looks for what Unicode character is setat the value 42. And that happens to be an asterisk. So if you want to convert back andforth between strings and numbers, then you’re actually going to need to pull in the stringconversion package, which you can find on go Lang under packages.If you scroll downa little bit, you see string conversion here. And this is going to expose all sorts of functionsthat are going to make it a lot easier to convert back and forth between strings andother data types. So in this case, what we’d want to do is use the string conversion packagesI to a function, which converts an integer, that’s the I two, that’s the two and thento an ASCII string. So if we go ahead and run that, now you see that it properly convertsthe integer 42 into the string 42, and prints it out for us. So if you need to work withconverting between numbers and strings, then go ahead and use that string conversion package.But if you’re converting between numeric types, just keep in mind, you can’t implicitly dothat conversion, you have to explicitly do it. And if you need to do that, then you cango ahead and use the type as a function.Okay, so we just covered quite a bit of ground.So let’s go through a summary of what we’ve talked about throughout this video. Okay, there’s quite a few things to keep inmind as we’re working with variables. So let’s go through and review what we talked about.The first thing that we talked about is the three different ways to declare variables.So we saw that we could declare a variable, and then initialize it later, we saw thatwe can declare it and initialize it at the same time. And then we also saw that we canuse this colon equals syntax as a shorthand version of declaring and initializing a variable.And then we let the compiler decide what type to assign to that. Now normally, you’re goingto use this third version, the only time you’re really going to use the second version iswhen the compiler is going to guess wrong.And then the first version is sometimes useful.If you need to declare the variable in a different scope than you’re actually going to initializeit. We then talked about how we can’t read declare a variable. So within the same scope,we can’t initialize that variable twice, but we can continue to reassign values to it,but we can shadow them. So if we declare a variable in a package scope, for example,we can read declare that in a function scope, and that’s going to shadow the variable atthe higher level of scope. All variables must be used in a go application. So if you declarea local variable, and that variable isn’t used in the scope that it’s declared or oneof its inner scopes, then that’s going to trigger a compiler error. And you’re goingto have to go back and clean that up before your application is going to run. And again,the reason that that’s really nice is as code evolves, and it continues to be refactoredand improved over time, and features get retired, you don’t have all these old variables hangingaround and requiring allocations of memory when they’re not being used for anything anymore.We also talked about the visibility rules.The first thing that you need to know is whenyou’re working with package level variables, a lowercase first letter means that it’s scopedto the package, which means all of the source files that are in the same package have accessto that variable. If you have an uppercase first letter, then it’s going to be exportedglobally, and so anything can work with that variable at that point. There is no privatescope. So you can’t scope it.Variable to the source code itself. However, you can scopea variable to a block by declaring it within the block instead of declaring it at the packagelevel. We also talked about the naming conventions. And there are really two naming conventionsthat are used Pascal case, which basically means you uppercase, the first letter, andcamelcase. So when you’re naming variables, you don’t want to separate the words in thevariables with underscores. You don’t want to have them all in lowercase, you don’t wantto do anything like that. Just use standard Pascal or camel casing rules. The only exceptionto that is if you’re working with acronyms, all of the letters in the acronym should beuppercase. The names of the variables should be as short as you reasonably can get them.So you’ve got a very short lifespan of the variable, say, for example, a counter in afor loop, then having a one letter variable name is perfectly acceptable.However, ifyou’ve got a variable that’s got a longer lifespan, say, for example, it’s used in afairly long function, or if it’s exported from the package, then having a longer moredescriptive variable name is certainly something that you should consider. However, pleasedon’t go crazy. Keep those names as brief and concise as possible. And the last thingwe talked about are the type conversions and how these work a little bit differently thanother languages, a lot of other languages, you would have to put the type in params,and then what you want to convert, in NGO, it acts more like a function. If we want toconvert an integer to a floating point 32 number, then we use float 32 as a function,and we pass the integer into it, and it’s going to do the type conversion for us, wealso learned that go does not do implicit type conversion.So if you try and take afloating point number and assign it to an integer, goes going to throw a compile timeerror for that. And that’s because of the possibility of losing information throughthat conversion. So every time you’re going to do a type conversion that might lose information,you’re going to have to do that yourself so that you’re making the decision. And thenyou can write whatever tests are required in order to make sure that information hasn’tlost. The final thing that we learned is when we’re working with strings, then type conversionscan start to get a little bit weird.So in order to handle the conversion between integersand strings, and other data types in strings, we can use that string conversion packagethat offers a series of functions that make sure that the conversions happen the way thatwe expect them to. In today’s video, what I want to do is introduce the primitive typesthat we have available in the go language. Now, we’re not going to be talking about everybasic type that you can create. There are certainly collections and some more complicatedtypes. And we’ll introduce those a little bit later. Today, I want to focus on threecategories of information that we can store and go. We’ll start by talking about the Booleantype, then we’ll move on to the numeric types. And in that category, we have integers, floatingpoint numbers and complex numbers. And then we’ll move on to the text types. Okay, sofairly simple agenda, but we’ve got a lot to cover. So let’s go ahead and get startedby talking about how we can work with boolean data in go.Boolean data is probably the simplesttype of data that we can work with and go. And it represents two states, you either havetrue or you have false. So in order to show you a simple example of working with Booleanvariables, we can create a variable here and make it of type bool. So that’s the data typethat you’re going to use when you’re declaring a Boolean. And we can set it equal to A values.So for example, we can set it equal to true, and then we can go ahead and print out usingour fancy printf statement here, we can printout the value and type of this Boolean.And if we run that, we see that the Boolean trueis in fact got the value true. And its data type is Boolean. So we can also initializethis to false, and run that. And now we see false is also a Boolean. Now there’s a coupleof uses for Boolean variables in our applications, perhaps one of the most common is to use themas state flags. So for example, say you’re creating an application and you want to storewhether a user is signed up for notifications when a report is generated. Well, you canuse a boolean variable in order to store true if they want that report or false if theydon’t. The other case. And perhaps the more common case for using Boolean and go is asa result of logical tests. Now, we’re not ready to talk about logical tests quite yet.But I can show you how Boolean ‘s are used in those tests.So if we create a simple variablehere, and we use the equals operator to test if one equals one, and then create anothervariable, and then I want to test if one equals two. Now, the double equals operator is calledthe equals operator. And that’s basically checking to see if the item on the left isequivalent to the item on the right, so one obviously equals the number one, and one,just as obviously doesn’t equal the number two. So if we print out the value of thoseusing these two printf statements, then we see that a Boolean is actually generated asa result of this equivalency test. Now when we get into talking about logical tests, we’llsee that there are actually quite a few other logical tests that we can use. But this isa very common use case that we have. So we see looks like I need to add a new line operatorhere, we see that the first operation does in fact, generate the Boolean true and thesecond operation generates the Boolean false.Now the other thing that’s important to knowabout the primitives is that every time you initialize a variable, Ingo, it actually hasa zero value. So we’re assigning the value of n and m in this example here, but whathappens is If I just do this and print out the value of that, well, in some languages,that would be uninitialized memory, and we would have no control over what printed out,when go, every time you initialize a variable, it has a zero value in the zero value forBoolean is the value false. So you don’t have to worry about initializing variables everytime.If the zero value is acceptable to you, you can certainly leave it like that. So Booleanis a pretty simple. The next type that I want to get into are the numeric types. And theseare a little bit more complicated, because of all of the different types of numbers thatwe can work with in our applications. Go has a rich array of numeric types to choose from.Now, the first thing that we need to know about is the zero value. And the zero valuefor all numeric types is going to be zero, or the equivalent of zero for that numerictype. So let’s start talking about the integer types. So the first type of integers thatwe can work with are the signed integers. And those have several different data types.So we have the general int, which is an integer of unspecified size.And I say unspecifiedbecause every platform can choose to implement it as a different size. Now, the one thingthat you’re guaranteed is regardless of your environment, and it will be at least 32 bits,but it could be 64, or even 128 bits depending on the system that you’re running on. Andthis is going to be the default integer type. So if we do something like n equals 42, andthen we print out the type of n, then you see that we get the value 42. And it’s oftype integer. Now, there are other types. So we can have eight bit integers, which canrange from negative 128 to 127. We can have 16 bit integers, which can go from negative32,007 68, up to 32,007 67, then 32 bit integers, which can go from approximately negative topositive 2 billion. And then if you need a really big number, you can go with 64 bitintegers. And those go somewhere between plus and minus nine quintillion. So if you needbigger numbers than that, then you’ve got a very large application that you’re workingwith. And in that case, you’re going to need to look into the big package from the mathlibrary, which can handle arbitrarily large numbers.So you can’t get a number big enoughfor the big package to not be able to handle. Although working with numbers at large, you’regoing to take a bit of a performance hit and the numbers aren’t going to be quite as easyto work with is using the primitive types that we’re talking about here. Now relatedto the signed integers are the unsigned integers. So we have the value 42 here, and just soyou can see, we can create an unsigned integer. And I’ll just pick at you and 16 and assignthat the value of 42. And then let’s go ahead and run that. And you see that now we havea un 16. So there’s an equivalent type of unsigned integer for every signed integer,we have you int eight, which is an unsigned eight bit integer which can go from zero to255. We have a 16 bit unsigned integer and a 32 bit unsigned integer. Now, what we don’thave is we don’t have a 64 bit unsigned integer.But we do have a type byte. And a byte isan alias for an eight bit unsigned integer. And the reason we have that is because theunsigned eight bit integer is very common, because that’s what a lot of data streamsare used to encode their data. Now with these integer types, and again, unsigned unsignedintegers are basically the same type, we’ve got several different arithmetic operationsthat we can do. And these are built into the language. So if I just dropped in this example,here, you see that we’ve got an integer, a set equal to 10. And we’ve got another integerbe set equal to three. And we’re doing the basic arithmetic operations that are availableto us. So we can add, we can subtract, we can multiply,we can divide, and then this percent sign here is actually used for the remainder. Soif I run this, you see that we get 10, plus three is 1310, minus three is seven, and soon. So we get the numbers that we expect, then the one that you might not expect isthis a divided by b.So 10 divided by three is three, remainder one. And so we get theresult three out, because when you divide an integer by an integer, you have to getan integer result. So the type cannot change during the operation. So when we do this,we’re doing what’s called integer division, and we dropped the remainder. Now, if theremainder is interesting, that’s what this remainder operator is for. And then we canpick up that remainder one out of it. Now, just like when we’re doing division, we can’tchange the type. So dividing an integer by an integer can’t give us a floating pointnumber, for example, we’re also not allowed to add to two integers of different types.So if we take this as an example, we’ve got the integer, a set equal to 10, and an eightbit integer set equal to three. And if we try and add those together, we’re actuallygoing to get an error. So even though go might be able to do that, theoretically, it’s very,very insistent that it’s not going to work across types without your consent.So in orderto make this work, we would actually have to do a type conversion on one of the variablesto convert it into the type of the other. So just like we talked about in the last video,where go is very, very hesitant about implicit data conversion. This is another example.Even though these integers are almost equivalent, go is not going to make that assumption foryou, you’re going to have to do the type conversion. Now a couple of other operations that we haveare called the bit operators. So if I drop in this example, we see the full Bit operatorsthat we have, we’ve got the AND operator, we’ve got the OR operator, we’ve got the exclusiveOR operator, and we’ve got the and NOT operator.Now what’s going to happen when we run this?Well, let me just run this first and get these results. So you see that if we take a andb, then we get two, if we take a or b, we get 11. And these might not make a lot ofsense. So in order to clear things up a little bit, let me put in the binary representationof these. And then we can walk through what these are doing. So 10 is 1010, in binarythree is 0011. Now when we run into an end operation, that’s going to look for what bitsare set in the first number and the second number. So as we can see, we’ve got four bitsin each one of these numbers that are allocated.Actually, these are 32, or 64 bits long, butI’m ignoring all the zeros at the beginning of these numbers. So let’s look at the fourdigits that matter. So if we look at these, then we see actually, if we add these together,we’re going to get 0010. And in binary, that is two, so 10, and three equals two. Now ifwe do the or, or means if one or the other is set, so we get one, because a has the firstbit set, neither one has the second bit set, both have the third bits set, so we’re goingto include that, and then B has the last bit set. So we’ll have that. So now we end upwith 1011, which is one plus two plus eight, which equals 11. Exclusive OR means eitherone has the bit set, or the other does, but not both. So in that case, we’re going todo 1001.The only difference between this and the OR operation is that third bit wherethey’re both set to true. And therefore we’re not going to include that. Now in the endnot that’s kind of the opposite of or because within not, it’s going to be set true onlyif neither one of the numbers have the bit set. So since the first bit is set in a, we’renot gonna include that, neither one has the second bit set, so we’re going to includethat both have the third bit set, so we’re not going to include that.And B has the fourthbit set. So we’re not gonna include that. So we get 0100, which is equivalent to thenumber eight. And that’s how these bit operations work. The last example that I have to showyou with integers is what’s called bit shifting. So when we have this example here, the firstprint statement is going to bit shift a left three places. And the second is going a bitshift a right three places. So let’s run this and see what that’s going to do. And so weget to number 64, and one, so in order to understand that, let me go ahead and put inthese values, so we can understand what’s going on. So eight is really two to the thirdpower.And when we do bit shifting, we’re basically adding to that exponent, as longas we’re dealing with the power of two, because really, what we’re going to do is we’re goingto take this to to the third and multiply it by two to the third, which is equivalentto two to the sixth, and two to the six is 248 1632 64. So that’s how we get the 64.Now, when we bit shift to the right, we’re going to take our original number, and we’regoing to divide it by two to however hard we’re shifting, so we’re going to divide itby two to the third. And in that case, we’re going to get two raised to the zero power.And any number greater than zero raised to the zero power is one. And so that’s how those operations work. Thenext data type that I want to talk about are the floating point types. So we have a lotof different integer types. So we can store a lot of different size numbers. But withinteger types, we can only store integers, so they can be positive or negative integersor zero, but we can’t store decimal numbers.So in order to store decimal numbers in go,we’re going to use the floating point numbers. Now the floating point numbers in go followI triple E 754. Standard. And in that standard, we’re going to pull out two of the types.So we’ve got 32 bit floating point numbers and 64 bit floating point numbers. So if you’reworking with a 32 bit floating point number, you can store numbers between plus or minus1.18 times 10 to the negative 38, all the way up to 3.4 times 10 to the 38. So fromvery small numbers to very large numbers. If you need even more precision than that,then you can use a float 64. And that can go from plus or minus 2.23 times 10 to thenegative 308th, all the way through 1.8 times 10 to the 308. So how do we create floatingpoint numbers? Well, here’s some examples of how we can do that. So line eight hereshows you how you’re going to define your flooding point literals almost all the time.So we’re going to declare a variable and set it equal to 3.14.And away we go. This nextline here shows that we can use exponential notation. So we can use 13.7 times 10 to the72nd. And that’s going to be able to use the short form iE 72nd to stand for that 10 tothe 72nd. So if I run this, we’re actually going to get the final result here, of 2.1times 10 to the 14th as a floating point 64. But notice we didn’t get any errors. So allthree of those declarations, syntaxes are okay, so that’s how we can work with floatingpoint numbers and show you how you can explicitly declare these We can use, let me just do varand float 32, for example, and initialize that.And that’s how you’re going to declarea floating point number. Now unfortunately, this number is a little big, because we canonly go times 10 to the 38th power. So if I comment that line out, things are goingto run properly. If I come back in and make this a floating point 64, then we can restorethis number. And that’s another thing that’s important. If you’re going to use the initializersyntax on a decimal, it’s always going to be initialized to a float 64. So keep in mind,you can’t do arithmetic operations between float 64 and float 30 twos.So if you’re justusing the initializer syntax, you’re going to want to make sure that everything’s workingas float 64. And if you forget, don’t worry about it, the compiler will complain at you,and you can quickly go in there and make sure that everything’s working properly. Okay.Now, speaking of arithmetic operations, let me jump in a couple of those. And you cansee the arithmetic operations that are available with floating point numbers. So if I run this,we get the expected answers of adding, subtracting, multiplying dividing two numbers together.Now, a couple things to notice here, when we divided A by B, we did in fact get a decimalresult, because as long as we’re working with floating point numbers on both sides, we canget a floating point result. As a matter of fact, we have to get a floating point result.The other thing to notice, we don’t have the remainder operator available that is onlyavailable on the integer types. Further, we don’t have the bitwise operators or the bitshifting operators. So if you need to work with those, you’re going to have to work withthe integer types.The last type of numeric primitive that we have available in go isthe complex type. And this is really kind of exciting because this is fairly rare inthe languages that I’ve worked with, where complex numbers are actually treated as afirst class citizen, and it opens up go to be used as a very powerful language for datascience. So if we come in and paste an example, you can see a very basic declaration of acomplex number.Now there are two types of complex numbers. There’s complex 64, and complex128. And the reason we have that is we’re basically taking a float 64 plus a float 64,or a float 32 plus a float 32 for the real and imaginary parts. Now here, I’ve got avery simple complex number, that’s one plus two I, if I go ahead and run that, you seethat in fact, it prints out as one plus two I and that’s complex 64. So goes parser understandsthe I literal as an imaginary number, and it uses that when you’re creating your variable.Now we can actually go even simpler than that, because AI is considered special. And we canrun this with just two AI and we get zero plus two I down here and the result. Now whatoperations that we have available. Well, we can do addition, subtraction, multiplication,and division again. So I’ve got two complex numbers defined here. If I run this, thenI get the expected result, where the real parts are added together, and the imaginaryparts are added together, or subtracted, multiplied, divide whatever operation we’re applying.Now, what happens if you need to decompose this down.So if I come back to our firstexample, here, where we have one plus two I, not every operation that I’m going to dowith these numbers is going to need this to work as a complex number. So what happensif I need to get at the real part or the imaginary part? Well, in order to do that, we actuallyhave two built in functions in the language. So let me wrap this in here with a call tothe real function.And then I can follow that up with its partner, which isthe image function. And what those are going to do is those are going to look at the complexnumber that you provide. And they’re going to pull out the real part or the imaginarypart. And these functions work with complex 64 and complex 128. So if you run this onthe complex 64, then the real and the image function are going to give you float 30 twosout, if you run this on complex 128, it’s going to give you float 64 is out becausethose are the data types used for the components.So if we run this, we see that we get float32 is out. If we convert this to a 128 and run this again, then we’re going to get float64 is out. And it’s going to break apart that complex number into the real and imaginarypart. So we can work with those however, we need to know the complement of these two functionsis the complex function. So if you’re working along in your program, and all of a suddenyou need to make a complex number. How do you do that, because you can’t use this literalsyntax. So in order to do that, we do have another function. And that’s the complex function.And this takes two numbers. The first number is the real part. And the second number isthe imaginary part. So let me go ahead and wipe out this line. Get rid of these realcalls here, and then run. And now that we see that we can take two floating point numbers.In this case, they’re considered to be floating point 60 fours because we’re making a complex128.And it creates five plus 12 I for us, the last data type that I want to talk aboutis the text type. And texting go falls into two basic categories. One, I can talk a lotabout the other we’re just going to touch on. So the first text type that we have availableis a string, and a string. Ingo stands for any UTF eight character, so that makes itvery powerful. But that means that strings cannot encode every type of character that’savailable. For that we need the other text type which we’ll talk about in a second. Butlet’s just start by introducing a basic example here. So here I’ve got a string literal, thisis a string, I’m going to print out its value and its type. So if I go ahead and run this,you see that this is a string print out. And it’s of type string. No big surprise here.Now one of the interesting aspects of a string is I can actually treat it sort of like anarray.Now, we haven’t talked about arrays yet. But I can actually treat this stringof text as a collection of letters. So if I do something like this, I’m actually goingto ask it for the third letter, because arrays and go are zero based. So I’m going to lookfor the 012. That’s the third letter in the string, which is the letter II. So if I runthis, I get an interesting result, I get the value 105. And that’s a un eight. So whatthe heck happened there? Well, what’s happening is that strings and go are actually aliasesfor bytes.So we can go ahead and convert this guy back, since a byte is just an aliasfor a string, and we can get our letter I back. Now, strings are generally immutable.So while I can inspect the second character, I can’t do something like this, if I triedto run this program, let me just print out the full string here and run this, then Iget an error. And there’s actually quite a few things wrong with this. The first thingis I can’t assign a string to a byte because I’d have to do a conversion. The second thingis I can’t manipulate the value of the string. Now with the numeric types, I should do thatthere were quite a few operations that we can perform with it, there is one arithmeticor pseudo arithmetic operation that we can do with strings, and that is string concatenation.Or in simpler terms, we can add strings together.So in this example, I’ve got the string sand the string s two. And as you can see down in the printf statement, I’m adding s&s twotogether, and then we’re going to print out the value in the type. So if I run this, yousee that it just merges all the strings together, and it gives us the result. Now another thingthat I can do with strings is I can actually convert them to collections of bytes, whichin go is called a slice of bytes.So in this example, I’m starting with a string, thisis a string, and then I’m going to do a conversion to this collection of bytes. And I’m goingto pass the string into that. So if we run that, we actually get this as a string comesout as the ASCII values, or the UTF values for each character in that string. And thenyou see that the result is a collection of UN eights, which is a type alias for bytes.Now, why would you use this one? It’s a very good question.A lot of the functions thatwe’re going to use in go actually work with byte slices. And that makes them much moregeneric and much more flexible than if we work with hard coded strings. So for example,if you want to send as a response to a web service call, if you want to send a stringback, you can easily convert it to a collection of bytes. But if you want to send a file back,well, a file on your hard disk is just a collection of bytes, too. So you can work with thosetransparently and not have to worry about line endings and things like that. So whilein your go programs, you’re going to work with strings a lot as strings. When you’regoing to start sending them around to other applications or to other services, you’revery often going to take advantage of this ability to just convert it to a byte slice.Okay, the last primitive data type that we have to work with is called a rune. Now arune is a little bit different than a string type in go.Because we’re a string type representany UTF eight character, a rune represents any UTF 32 character. Now, UTF 32 is a littlebit of a weird animal, because while any character in UTF, 32, can be up to 32 bits long, itdoesn’t have to be 32 bits long. For example, any UTF eight character, which is eight bitslong, is a valid UTF 32 character. So there’s all sorts of tricks that they have to do inthe encoding of the characters in order to know whether the character is one, two orfour bytes long. So that makes things a little bit tricky to work with and go. Now we’renot going to get too deep into this subject, we’re just going to talk a little bit aboutwhat runes are.And then I’m going to point you to some things that you can refer to ifyou actually need to work with rooms in your application. So if we look at this example,here, we’re declaring the room a. Now notice the difference here, if we were declaringa string, we would have double quotes. When we’re declaring a single room, we use singlequotes. But if I run this, I’m going to get an interesting result.Notice I get the value97. And it’s an int 32. Now that might seem a little weird. And the reason for this isbecause runes are just a type alias for int 30. twos. So we’re strings can be convertedback and forth between collections of bytes. Rooms are a true type alias. So when you talkabout a rune and go it is the same thing as talking about an integer 32 name, I think,well, that’s just because we’re doing some implicit initialization here, we’re usingthat colon equals syntax.So let’s specifically and explicitly declare this as a rune andtry this again. And we get the same result. And again, that’s because a rune is an integer32. Now, you might be feeling a little lost here. So if I’ve got a UTF 32 characters athow do I work with that. Well, the Answer comes from the go API’s. So if I jump outto go lang.org, come into the packages. And let me just jump to the strings package. Andthen I’ll show you this. Notice this function here, read rune. So if you’re working witha data stream that’s encoded in UTF 32, then you have special functions that you’re goingto be able to take advantage of, that’s going to return those values out. So if we do readbyte, which is going to read a single character, then we’re going to get a bite out and a potentialerror.But with read rune go is going to look at the byte stream, it’s going to pull offthe next room that’s available to you the size of that room, and then a potential error.So you’re going to have all the information you need in order to re encode that integer32 that you’re going to have back into its UTF 32 character. So things are a little bitmore tricky when you’re working with runes. And you’re going to have to read into theAPI’s for the go package that you’re working with, in order to understand how to work withthem in your application. Okay, so that covers the primitive data types that you have towork with and go, let’s go into a summary and review what we’ve talked about in thisvideo. We covered a lot of ground in this video,and I understand that it might take a little bit of time to process this and really understandall the different options that you have for primitive data types and go.Now before weget into the summary, I do want to let you know that a lot of times the default datatypes that you’re given are going to be perfectly fine. So if you’re working with Boolean, you’regoing to get a Boolean type, if you’re working with integers, you’re going to get that signedinteger type floating point, it’s going to give you a floating point, 64, and so on.So you don’t have to memorize every single data type. If you need a specific data type,then you can certainly refer to the NGO documentation in order to find out what’s available foryou. So let’s go through and review what we talked about. The first thing that we talkedabout was the Boolean type of data, we found out that it can take two values true or false.And it’s not an alias for other types.So in some languages, a Boolean is actually analias for an integer. So you might use like negative one for true and zero for false whengo Boolean is its own type. So you can’t convert back and forth between integers and thingslike that, you’re going to have to work with Boolean as their own type. We also talkedabout the zero value for a Boolean is the value of false. And so if you initialize aBoolean and don’t set a value for it, it’s going to receive the value false. Then wetalked about the numeric types. And the first type that we talked about were the integertypes. And that broke down into two different types with the signed integers. And thereare two classes, I guess you could say within the sign integer type. There’s the INT type,which has varying size, but a minimum of 32 bits. And this is going to be the most commontype of integer you’re going to deal with in your applications.But if you need a littlebit more granularity, or a little bit more resolution, or control over how much memoryis assigned to the integer, then you can go all the way from int eight, which is an eightbit integer all the way up to 64 bit integer, we also have the unsigned integers where thesigned integers have a plus or minus and so they can’t store numbers quite so large becausethey have to store a plus or minus bit. The unsigned integers can store larger numbers,but they can only ever be positive. And we have all the way through an eight bit whichwe can use the byte or the UN eight, type four, all the way through 32 bit unsignedintegers with the un 32.We have various arithmetic operations that we can perform on both integertypes. So we can do addition, subtraction, multiplication, division, and that remainderoperation. So remember, division with integers is going to give you an integer result. Soyou’re going to lose that remainder portion. So if you need that, you can use that remainderoperator to get it. We also have the bitwise operators. So we can do and or Exclusive OR,and the and not operations. And the zero value for any integer type is going to be the literalvalue zero.So when you initialize an integer type, and don’t assign a value to it, that’sgoing to be equivalent to the value zero, you’re not just going to get whatever wasin memory when that variable is initialized, and you cannot mix types in the same family.Now, this is going to be true throughout all of the numeric types. If you have a un 16,for example, and a un 32. And you cannot add those together, you’re going to get a compiletime error. The next numeric type that we talked about where the floating point numbers, so they follow the I triple E 754. Standard,there’s zero value is similar to the integer types, the value is zero. And we have twodifferent versions, we got 32 bit versions and 64 bit versions that we can work with.And we have several different literal styles that we can use to initialize them. So wecan use a pure decimal like 3.14, we can use exponential notation, for example, 13 e 18,or two e 10.And it doesn’t matter if that e is upper or lowercase, or you can do mixed.So for example, 13.7 e 12 is a perfectly acceptable way to initialize that. We do have addition,subtraction, multiplication and division that we can do with floating point numbers. Nowwe don’t have the remainder operation, but the division operation is going to give usa true floating point result. So we’re not going to lose our decimal portion. The finalnumeric type that we talked about were the complex numbers. The zero value of a complexnumber is zero plus zero I and they come in 64 and 28 bit versions and the reason forthat is the two components, the real and the imaginary component are either going to befloating point 32 or floating point 64.So when you add those together, that’s whereyou get the 64 and 128 bit versions. We have Some built in functions that we can work with.So we can use the complex function in order to create a complex number, we can use thereal function in order to get the real component. And we can use the match function in orderto get the imaginary component of a complex number.Now what the data type that comesout of that depends on the size of the complex number going in. So complex 64 is going togive you a float 32 out from the real in the match function and a complex 128 is goingto give you a float 64 out of the real in the match function, we have the same arithmeticoperations as we do for floating point numbers, we can do addition, subtraction, multiplicationand division. The final category of primitive data that we talked about, or the text types,and in go, there are really two different text types. The most common one that you’reprobably going to deal with are strings. No Strings are represented as a collection ofUTF eight characters, they’re immutable, you cannot change the value of a string afterit’s been initialized. You can concatenate strings together with the plus operator. Andthen you can convert them back and forth between a collection of bytes with this square bracketbyte syntax and passing in the string that’ll convert it to a collection of bytes.And youcan convert a collection of bytes back to a string by using the string conversion. Theother type we talked about is a rune and a rune represents any UTF 32 character. Nowrunes are a little bit more complicated to work with because of the multi step processthat it takes in order to encode a character into the UTF 32 character set. So when we’reworking with runes as a primitive type, really all we’re working with is an alias for aninteger 32. Today, I want to talk about constants and how you can use them in your NGO applications.Now, there are several things that we need to talk about with constants. So like we’vebeen doing, I want to break this down into several categories. The first thing that Iwant to talk about is how we’re going to name constants in our NGO applications.Then we’lltalk about type constants, followed by a discussion about untyped constants. And we’ll talk aboutthe differences between those two, and the options that each one gives us. And then we’lltalk about a method of generating constants that are called enumerated constants. Andfinally, we’ll end our discussion by talking about enumeration expressions, which are goingto build upon the concepts that we’re going to talk about in that first enumeration discussion.The first thing that I want to talk about is how we’re going to name our constants.So all constants are going to be preceded with the const keyword, that’s going to letthe compiler know that that’s what we’re trying to work with. Now, if you’ve come from otherlanguages, you might be expecting that we’re going to name our constants, something likethis, where we’re going to have all uppercase letters and separate the words with underscores.The problem with that is if we do that and go, then the first letter is going to be uppercase.And as you remember, from our discussion on variables, if we’ve got an uppercase firstletter, that’s going to mean that the constant is going to be exported.And we don’t alwayswant that. So instead of this, we’re actually going to name our constants the same way thatwe named variables. So if we had a variable that we wanted tocall my const, and we didn’t want to export it, then we would start with a lowercase firstletter, or in other words, we would use camel casing. And if we did want to export thissymbol, then we would simply change that first character to uppercase. Now assuming thatwe’re going to be working with an internal constant, then we’re going to switch thisback to a lowercase first letter. And then let’s talk about how we can create what’scalled a typed constant. Now a typed constant is created very similarly to a typed variable.So we can start with the const keyword, then the name of our constant, and then we’re goingto list the type of the content, and then we can set it equal to a value, then if wewant to prove that that worked out the way we expected it to, then we can go ahead andprint out the value in the type of the constant.And we will do that by using this printf statementhere. And then when we run this, we see that the constant is in fact created. It’s gotthe value 42 that we assigned, and it’s got the type that we assigned to it. Now the reasonit’s a constant and not a variable is it has to remain constant. So if we tried to do somethinglike this, change this to the value 27, then the compiler throws an error, because we’renot allowed to change the value of a constant. Another characteristic of a constant is thatit has to be assignable at compile time.So for example, if I wanted to have a constantthat represented the sine of pi over two, then I might be tempted to do something likethis. I’ll create a float 64 constant. And I’ll set it equal to the result of the sinefunction from the math library. And I’ll pass in 1.57, which is approximately pi over two.And then I can run this right? Well, the problem with that is in order to determine the sineof that value, that actually requires the function to execute, which is not allowableat compile time. And so you can’t set your constants equal to something that has to bedetermined at runtime. And that includes things like setting it equal to flags that you passinto your application, when you run, if you’re going to do that you can’t use a constantto store that value. Now constants can be made up of any of the primitive types thatwe talked about in the last video.So if we have this example, here, we’ve got an integerconstant, we’ve got a string constant, a floating point constant and a Boolean constant. Andif we run this, we see that all of those printout exactly the way that we expect. We’ve gotthe integer the string, the floating point value and the boolean value. Now in an upcomingvideo, we’re going to talk about the collection types and the collection types. are inherentlymutable. So for example, you couldn’t create an array and declare that to be a constanttype. Arrays are always going to be variable types. Now another characteristic that constantshave in common with variables is they can be shadowed. So if we create a constant atthe package level, and let’s just make this an integer 16, and set it equal to the value27, then we’ll delete these guys.And also these guys. Now we’ve got a constant calleda declared at the package level, that’s an integer 16. And then we got a constant inthe main function, that’s also called a and it’s an integer type. So if we update Thisprintf statement to print the type of variable, we see that the looks like I need to printmy variable twice, we see that the inner declaration of the constant wins. So not only can we changethe value of the constant, but we can also change the type because the inner constantshadows that outer constant. And we can prove that by commenting this line out, runningagain. And we see that the package level constant wins. So you want to be a little careful here,because if you’re going to reuse constant, it’s going to feel like those values are changing.So I wouldn’t recommend that you take advantage of this.But if you do get into a situationwhere constants aren’t evaluating the way that you expect them to, this is one possiblereason. Now when we’re working with constants, they work very similar to variables when we’reusing them in operations. So if we bring this line back, and set it equal to 42, and thenwhat I want to do is declare a variable. So we’ll declare a variable b as an integer,and set that equal to the value 27. And then we can do a plus b. And let’s see what happenswhen we do that. So if we run that, we in fact, get the ability to add a constant toa variable, and the result is going to be a variable. And so since the constant andthe variable are of the same type, we can perform the addition operation on there. Now,our constant is of a different type. For example, if we made variable b in 16, and run this,then we get exactly the same failure that we get when we try and add two variables ofdifferent types together.Now, so far, all we’ve been talking about are these type constants,we’re after the constant name, we list the type. But we don’t have to do that, we canuse the compilers ability to infer the type for us. So let’s just go ahead and do thatwith this example here. When we run this, we see that the constant a is inferred tobe an integer with the value 42. Now given that, given that the compiler is inferringthe value, what do you think is going to happen? If we do something like this, if werestore that previous example, where we’re going to add this constant to an integer 16?Well, in fact, in this case, the operation succeeds, which might be a little bit confusing.But the reason that works is because what the compiler is actually doing, when it seesthis constant is it’s basically replacing every instance. So the way the compiler seesthis program is it sees it like this. So since we’re taking a literal 42, and adding an int16 to it, that 42 is interpreted as being an integer 16.So the compiler doesn’t say,oh, constant, a equals 42, that’s an integer and always an integer. Instead, the compileris going to look for every time that we use the symbol a, and it’s going to replace thatwith the value of the constant. And so we can do these implicit conversions when we’reworking with constants, which is something that we can’t really do when we’re workingwith variables. The next thing that I want to talk about are what are called enumeratedconstants. So let me go ahead and start that conversation out by wiping out what we havehere, clean up our code just a little bit. And then I’m going to do this at the packagelevel. Because this is where I’ve seen these most commonly applied, you could do thesein a function level, if that made sense in your application. So I’m going to declarea constant a, and I’m going to have that as an untyped constant.And I’m going to setit equal to this special symbol called Iota. So when I run this, you see that a is evaluatedto have the value zero, and it’s inferred to have the type integer. So what is Iota?Well, Iota is a counter that we can use when we’re creating what are called enumeratedconstants. So in this example, having an enumerated constant isn’t terribly valuable. But oneof the things that I can do with constants is I can actually work with them in a constantblock like this. So when I’m doing this, I can create another constant set that equalto Iota and another constant and set that equal to it, let’s go ahead and clean up thisbecause we already know what the type is going to be. So we don’t need to be printing thatout. And then let’s print this command out two more times, switching to B, and C. Sonow we’re using Iota three times and when we get the result we actually see Iota ischanging its value as the constants are being evaluated.So the first constant that’s assignedhas the value of zero than one and then to know another special feature that we can takeadvantage of with Iota is that if we don’t assign the value of a constant after the firstone, then the Pilar is going to try and infer the pattern of assignments. So in this example,we would expect to have an error because B and C don’t have a value assigned. But sincewe’ve established a pattern for how to name the constants in this block, when we run,we actually get the same result.And that’s because the compiler is going to apply thesame formula. So it’s going to apply b equals Iota and C equals Iota for us. Now that valueof Iota is scoped to that constant block. So we create another constant block. And inthis case, we create a constant called a two and set that equal to Iota, copy this line,bring it down, and print out the value of a two, then what we’re gonna find is Iotaresets to zero. So Iota is scoped to a constant block. And what that lets you do is you canactually create related constants together, ensure that they have different values. Andthen if you have another set of related constants, you can start another constant block and ensurethat they have unique values, but allow duplication between the values in one constant block inanother.So what’s an example where you might use this? Well, let me just drop in this simpleapplication. And what we’re doing here is we’re setting up a constant block, where maybewe’re trying to store the specialty of veterinarians in a veterinarian clinic so that our narinecould be a cat specialist or a dog specialist, or maybe we can take his neck specialist to.Now as you can see, inside the cost box, I’m setting the cat specialist equal to Iota.And then in the main block, I’m creating a variable and setting its value equal to catspecialist. So if I check to see if the specialist type is a cat specialist, then I in fact,get the value true. Now, that works just fine. And this also works if I, for example, usea dog specialist, assign that specialist type to be a dog specialist run that, then that’sgoing to work out just fine.So everything looks really good here, right? And this isa very common use for enumerated constants. However, one thing that I would warn you about is what happensif I declare this variable and don’t initialize it to a type? Well, if I check to see if it’sdog specialist, I get false, which makes sense. But remember, what is the initial value ofIota? Well, the initial value of Iota equals the zero value for an integer. And so in fact,even though we haven’t specified a specialist type, it does show up as the value can’t specialist.So what do we do about this, so there’s a couple of approaches that we can take here.The first is to use the zero value of the constant as an error value.So we can setthis equal to error, then we don’t need this statement anymore. And now when we check tosee if the specialist type is a cat specialist, we get the value false because cat specialistsis equivalent to the integer value one, which is no longer the zero value of the integer.This is a very valuable approach, if you want to check to see if a value hasn’t been assignedto a constant yet, so you can specify an error specialist. And then you can check to seeif that value is set equal to the zero value of that constant. And if it is, you can handlethat error, because presumably, you expect that to be initializedin some way. Now, if your application guards against that, and there’s no reasonable wayfor this to happen, then you can take advantage of this underscore symbol, which is goes oneand only write only variable. Now what’s the value of a write only variable? Well, withIota, we have to have a zero value, we always have to start with zero.But if we don’t careabout zero, then we don’t have any reason to assign the memory to it. So we can usethis underscore symbol. And we’ll see this in quite a few places in our go applications.And basically, what that tells the compiler is yes, I know you’re going to generate avalue here, but I don’t care what it is go ahead and throw that away. So if we run ourapplication, again, everything works just fine. But in this case, we can’t actuallyget at the zero value of this constant block. Now the ability to create it lists of enumeratedconstants with a Oda is very valuable. But things don’t actually stop there. And thereason is, remember, the value of a constant has to be able to be determined at compiletime, but there are some operations that go is going to allow us to do for example, wecan do addition. So if we do this and run, then we get false again. But what happensif we print out the value of kept specialist if we do that, and we’re going to have toremove this line, then in fact, that expression got evaluated.So the first line line eightis evaluated to Iota plus five, which is zero plus five, the next line cat specialist, Iotaincrements, and the formula repeats. So cat specialist is equal to the value six, dogspecialist is seven, and snake specialist is eight. So this can be valuable if you needsome kind of a fixed offset. Now a common use case for this is to use the bit shiftingoperators because anything that we can apply to our primitive type, we can apply here aslong as it’s not a function expression. So we can do addition, subtraction, multiplicationand division, we can do remainder operations, we can do the bitwise operations.And we cando bit shifting, which is one of the more interesting use cases that we can take advantageof. And the reason is because we don’t have the ability to raise two powers because raisingtwo powers and go is a function in the math package. So we can’t do that in our constantevaluations. But by bit shifting, we can raise things to the power of two, because everytime you shift the number one level, you’re actually multiplying it by two. So we havethis example here. And I actually stole this from the effect of go article on golang.org.So what we have here is we have an example of a constant block that’s giving you constantsthat are equivalent to kilobyte, megabyte, gigabyte, terabyte, petabyte, and so on.Sodown here, in our main program, what I’ve done is initialize the file size to some arbitraryvalue. And then I’ve got this printf statement. And this is basically going to format a resultto print two decimal places, and then the literal string GB afterward. So this stringhere is basically saying I’m expecting to format a floating point number, and I’m goingto give it two decimal places, this GB is a literal GB, that’s going to be printed inthe result. And then we’ve got the value that’s going to be used to fill this in. And that’sgoing to be file size divided by the GB constant.Now you notice this constant block is setequal to one, and then we’re going to bit shift that value 10 times Iota. So the firsttime we’re going to bit shift 10 times one, so we’re basically going to multiply thisby two to the 10th. And then we’re going to multiply by two to the hundreds for the megabyte,and then two to the 1004, gigabyte, and so on. So when we run this, we get a really convenientway to format an arbitrary file size into a human readable format. And in the effectivego article, it actually shows you how to put a switch block, which we haven’t talked about.So you can make a decision about which constant you’re going to use based on the size of theincoming value. So here, we get this nice way to format this relatively difficult numberto read to be the very easily read 3.73 gigabytes. Now another thing that can be very valuableto do is using bit shifting in order to set Boolean flags inside of a single byte. Soif I paste this example in, we can see an example of that.So let’s just say that we’vegot an application and that application has users and those users have certain roles.So inside of this constant block, here, I’m defining various roles that we can have. Sofor example, you might be an admin, you might be at the headquarters or out in the fieldsomewhere, you might be able to see the financials or see the monetary values. And then theremay be some regional roles. So can you see properties in Africa, can you see propertiesin Asia, Europe, North America, or South America. So in order to define these constants, whatI’m doing is I’m setting the value to one bit shifted biota. So the first constant isadmin is one bit shifted zero places, so it’s a literal one, the second one is one bit shiftedone place, that’s two, and then four, and then eight, and then 16, and so on. So what I have is each one of these constantsis going to occupy one location in a byte.So down here in the main program, I’m definingthe roles in a single byte. And I’m oaring together is admin can see financials and cansee Europe now if you remember, oaring, is going to be set to true if one of the valuesis true, or the other one. So his admin has the binary representation of 0000001. I thinkthat’s enough zeros, seven zeros, followed by one can see financials is going to endup with 100, can see Europe is going to end up with the value 100000. And so when we orderthose all together, we’re going to get this byte that has these three flags set to true.So when we run this, we see that we’ve encoded eight access roles for user into a singlebyte of data. So we’re able to store this information extremely efficiently.So if Iwant to see for example, if this user is an admin, I can go ahead and print his admin,and then print out the value. And then in order to determine if that’s valid or not,then I can do a little bit of bitwise mathematics here. So I can take the constant is admin,and that with the roles, and what that’s going to do is that’s going to apply what’s calleda bit mask. So only the bits that are set in the is admin constant, and our roles aregoing to be left as true, which means if we’re an admin, we’re going to have the value oneset at that first bit. And then I can compare that to the is admin constant. So when I runthis, if we have the admin role, then we’re going to get the value true. Now, if I checksomething that I don’t have the role, so let me go ahead and copy this down. And then let’sjust see if they’re at the headquarters, so we’ll put that in here.And it’s exactly thesame bitwise operations, we’re just changing our mask. If we run this, we see that is headquartersequals false Actually, let me put in my Line return here, and then run this again. Andyou see that is headquarters equals false. So we can very quickly and very efficientlystore a lot of different information about what roles and access rights a user mighthave, and a simple byte. And having this constant defined with a numeration expression makesit really fast and really efficient and really clear in our application. Okay, so let’s gointo a summary and review what we’ve talked about in this video. constants are anotherone of those foundational elements, that is going to be a part of almost every applicationyou’re going to write. Now, the first thing that we learned about with constants is thatthey’re immutable, but they can be shadowed.So we can create a constant, we cannot assigna new value to it. But if we create a constant on an inner scope from an existing constant,then not only can we change the value, but we can even change the type, because thatinner scope is going to shadow the outer scope constant, they have to be replaceable by thecompiler at compile time, so the value must be calculable.So we’re not gonna be ableto access functions or command line arguments in order to determine the value of the constantsin our application. But we are going to be able to do simple expressions like we talkedabout in the enumeration section. They’re named like variables. So if you want to exportthe value of the constant outside of your package, then you’re going to use Pascal casing.And if you want to leave it as an internal value to the package, then you’re going touse camel casing to name that constant.Type constants work just like immutable variables.So you can use them in arithmetic operations, you can pass them into functions, but theycan only interoperate with the same type untyped constants have a little bit more flexibility.So they work just like the literals. So if you replace that constant throughout yourapplication with the literal value of that constant, that’s how it’s going to work. Sothat’s going to allow us to interoperate with similar types. So we had the value 42 definedas an untyped constant.And we could add that to an integer 16, we could add that to aninteger, we can add that to a un 16. Any of those would work, because the literal 42 willwork in all of those cases. Then we talk about the enumeration types that we can work with.And we learned about the special symbol Iota. That allows us to start with as values zeroand increments one time every time we use it inside the same const block. Now the onething that we have to watch out for is that constant values that match the zero valuesof variables can cause subtle bugs in your application, because you might have logicthat you expect it to initialize the value of the constant. And if something happensand then initialization doesn’t occur, then you’re going to be working with zero value,which might give you a false match to a constant that you’re evaluating against. Using that Iota operator, we canactually create what are called enumeration expressions. So we can define the value ofthe constant dynamically by combining Iota with any arithmetic bitwise operation, orbit shifting operation that’s allowable with the primitive type that the constant and representing,I want to talk about the first two collection types that we have available and go arraysand slices.Now, arrays form the basis of slices. So I want to start a discussion withthose. And when we talk about arrays, we’re going to talk about how to create them thebuilt in functions that go offers us to understand what’s going on with our arrays. And thenwe’ll do some exercises working with arrays and see how we can use those in our applications,then we’re going to follow the same pattern, but we’re going to switch over to slices.So we’ll learn the various ways that we can create slices, we’ll learn the built in functionsthat we can use to understand what’s going on with our slices.And then we’ll do someexercises working with those. Okay, so let’s go ahead and get started by learning how tocreate an array. So the first thing that I want to discuss about arrays is the use casefor them. Why do we need them and what are they used for? So let me just drop in an example,let’s just say that we’re building an application that’s going to work with the grades of studentsin a class.So with that arrays, we’re going to end up with an application something likethis, we’re going to have maybe grade one, grade two, grade three, and then we can printout those grades. So we can go ahead and run this. And we see that we get the scores 9785and 93 printed out. Now this works sort of. But we got a lot of problems here, becauseour application needs to know exactly how many grades we have to work with, at the timethat we’re designing the application. And working with these grades as a collectionbecomes very cumbersome. So enter the array, and that’s going to solve all of our problems.So in order to see what an array looks like, let’s go ahead and delete this code here.And then we’ll create an array, that’s going to hold the grades for us.Now the way wedeclare an array is we’re going to start with the size of the array. So we’re going to usesquare brackets and then we’re going to have an index that’s going to be the number ofelements that are array can hold, and then the type of data that the array is going tobe designed to store. So an array can only store one type of data. So in this case, we’redeclaring an array of integers that can hold up to three elements. If we wanted to holda different type, say we want them to have an array of strings, then we would type thisto a string, and so on. So you have to specify at the time that you’re declaring the array,what type of data you’re going to store. And then we can use this initializer syntax Toput in the values for our array, so we can put in the same scores that we had before9785, and 93. And then, if we come into our print statement here, and add our grades aswhat we’re going to print, then we see that we have all of the grades printed out togetherin this collection called an array.Right now, that’s a convenient collector. As westart getting into looping constructs and things like that, we’re going to really findthat having things grouped into arrays and slices and the other collection types is avery powerful way for us to work with our data. Now, another advantage that we havewith working with arrays is the way that they’re laid out in memory. So if you declare threedifferent variables and specify their values, it’s impossible to know how they’re goingto be laid out by the go runtime with arrays.However, we know by the design of the languagethat these elements are contiguous in memory, which means accessing the various elementsof the array is very, very fast. So by collecting our data together in arrays, not only is iteasier to work with, but it also makes our applications generally a little bit faster.Now one problem that we have in this example here is if you look at it, we’re actuallydeclaring the size of the array twice, because we have this syntax here, where we’re sayingthat we’re creating a three element integer array, but then we’re adding three elementsto it. And that’s not really required. If you’re going to be initializing an array literallike we’re doing here, then you can actually replace the size with these three dots here.Basically, what that says is create an array that’s just large enough to hold the datathat I’m going to pass to you in the literal syntax. So in this case, we’re going to getan array that has three elements in it.And that’s implied by the fact that in this literalsyntax, we’ve passed three integers to it, we can also declare an array that has a certainsize, but has its values zeroed out, by doing something like this, if we declare an arraycalled students, and let’s make that a three element array that’s going to hold strings.And then let’s print out what we have in that array. So if we print out, students, makesure I’m spelling everything correctly and run this, then we see that we have an arraythat’s empty.So we have declared a three element array that can hold strings. But obviously,there’s no elements in there right now. So in order to specify a value in the array,we’re going to use this syntax, so we’re going to call upon the array, and then we’re goingto tell it which index we want to work with within the array. So in this case, we’re workingwith the zeroeth index of the students array. And then let’s just assign the name Lisa toit, then we can go ahead and print out our arrayagain, and run it. And now we see that we have, I always forget to add this line returnhere, then we see initially we have an array of students that’s full of empty strings.In the second instance, we’ve actually specified that first element. Now you may be wonderingwhy we’re starting with the value zero. And the reason is related to how arrays are madeup of contiguous blocks of memory. So when we talk about students as the name of thearray, what go is going to do is it’s going to have a pointer or it’s going to rememberthe location of the beginning of that array.And then the index that we pass in this casezero, is going to tell it how many strings to walk forward. So it knows that when ithas a string, a string has a certain length. And so it’s going to walk that many strings.So when we pass zero, it’s going to be the head of the students array moved forward zerostring elements. And so that’s going to be the first element of our array. So we canfinish this example out, if I drop some code in here, we can see what it would take tofill out this array.So in this case, we got the zeroeth element to Lisa, the first elementis Ahmed. And the second element is Arnold. So if we print that out, we see the expectedresult, where we have Lisa, Ahmed and Arnold. And it doesn’t matter what order we work withthese, if we flip these around, then we find that they do flip around in the array, wecan assign them in any order that we want. Now if we want to get add a specific elementin the array, then we can use this square bracket syntax again, and dereference theelement from the array. So if we do this, and then change our label again. So we’regoing to get the second element of the array, which is index one, then we can go ahead andrun this. And then we see that the second element has the value of Arnold.So we canuse this square bracket syntax in order to assign values to the array, as well as topull out the values that have been assigned. Now another thing that we can do is we candetermine how big the array is. Now, obviously, we created the array up on line eight. Sowe remember at design time that we created this, but there may be a situation where youneed to go back and review the size of the array that you’re working with. And the waythat we can do that is using the built in length function. So if I drop in another printstatement here, and format that, you see that we can get the number of students in arrayusing this built in alien function and passing in the array. So if we run this, then we seethat we get the number of students equals three and that’s going to print out the sizeof the array. So if we change the size of the array to say five then the results ofprinting The array isn’t going to change, but the size of the array does.Now one thingthat’s important to remember is that an array can be made up of any type, it just alwayshas to be the same type for a given array. So we’ve been working with arrays of integersand arrays of strings. So we’ve been working with primitives. But this example here showsthat we can actually make up arrays have anything else. So in this case, we’ve got an arrayof arrays. So let’s just say that we’re working with some linear algebra. And we need theidentity matrix, which is a concept that’s used pretty often in linear algebra. So thisarray here stores a three by three identity matrix.So the first row is going to holdthe values 100, the second row is going to hold 010. And the third row is going to hold001. So if we go ahead and print this out, then we see that we do in fact, get thosevalues. Another way to look at this, and maybe a little bit easier to see is using this wayhere. So we’re just going to declare the array of arrays, and then we’re going to initializeeach one of those rows individually. So this reads a little bit cleaner, and might be alittle bit easier for you to understand what’s going on. And if we run this, we get the exactsame result. Now the last thing that I want to talk about with arrays is something that’sa little bit different with arrays and go than in other languages. And that is thatarrays are actually considered values. So in a lot of languages, when you create anarray, it’s actually pointing to the values in that array.So if you pass things around,you’re actually passing around the same underlying data. But in go, that’s not true. When youcopy an array, as we’re doing on line nine, here, you’re actually creating a literal copy.So it’s not pointing to the same underlying data is pointing to a different set of data,which means it’s got to reassign that entire length of the array. So if I run this, you’llsee what I’m talking about here. So on line eight, I assigned an array on line nine, Icreated another variable b and assign that to a, and then on line 10, I changed the secondelement of the array to the value five. And what you see is that when I print out thearray, it has the original values 123. But B has the new values of 153. So when you’reworking with these, you have to be a little careful, because copying arrays, especiallywhen we get into functions, if you’re passing arrays into a function, go is going to copythat entire array over. So if you’re dealing with a three element array, that’s not a bigdeal, if you’ve got a million elements in your array that could slow your program downa little bit.So what do you do if you don’t want to have this behavior? Well, we haven’ttalked about it yet. But I want to give you a hint right now in order to cover this completely. And that is this idea of pointers. So theway that our program is working right now is that the value B is assigned to a copyof the array. But if we do the address of operation, which is this character here, thenwhat we’re saying is B is going to point to the same data that he has.Now we’ll get intomore detail about what this means later. But the long and the short of it is if I run this,now, A and B are pointing to the same data. So A is the array itself, and B is pointingto a. So when we change the value in line 10, we’re actually changing the same underlyingdata for both. So when we print them out, we see that the array has changed, as wellas the array that B is pointing to, because they happen to be exactly the same array.Now arrays are very powerful. And there’s a lot of use cases where you can use arraysvery efficiently. However, the fact that they have a fixed size that has to be known atcompile time definitely limits their usefulness. So in go, the most common use case for usingarrays is to back something called a slice.So let’s take a look at a slice. So the firstthing that I want to do is comment out a couple more items in this example here. So we’llcomment on this one, this one and this one. And then we’ll change this over to slice syntax.So the way we’re going to do that is simply by eliminating these three dots here. So aslice is initialized as a literal by just using the square brackets, the type of datawe want to store. And then in the curly braces, we can pass in the initialized data. So wego ahead and run this, we see that we get the values 123, it looks exactly like an array.And as a matter of fact, everything we can do with an array we can do with a slice aswell, with one or two exceptions.So in order to illustrate that, we have the length functionthat we talked about with an array, well, we have the length function with a slice aswell. So if I run this, we see that we do get the length of three. So we initializethe slice with values 123. So with three elements, so the length function gives us a value ofthree. Now there’s an additional function that we have available with slices, and thatis the capacity. And that’s because the number of elements in the slice doesn’t necessarilymatch the size of the backing array, because the slice is really a projection of that underlyingarray.So we can have a very large array and only be looking at a small piece of it. Nowif we run this example, we see that the capacity function returns the value three. So the underlyingarray is exactly the same size as the slice. But as we go along here, we’ll see how wecan get into situations where the length and capacity are different, and why that’s a verygood thing. Now unlike Like arrays, where we have this syntax here, andwe have to use this address of operation in order to point to the same data slices arenaturally what are called reference types.So they refer to the same underlying data.So if we run this example, again, remember when we ran this with an array, we saw thatB store different data than a when we were done. So if we run this, we see that A andB are actually pointing to the same underlying array. And so when we change the value inB, we get a change in the value in a. So this is one thing that you’re going to have tokeep in mind when you’re working with slices. If you got multiple slices pointing to thesame underlying data, you have to keep in mind, if one of those slices changes the underlyingdata, it could have an impact somewhere else in your application. Now, so far, we’ve onlylooked at the literal syntax for creating a slice. And that’s what we’re seeing hereon line eight, there’s actually several other ways that we can create slices. And that isillustrated with this example here. So you see on line eight, we’re creating a slicethat has the values one through 10.And then on line nine, we’re creating a slice B, andthat’s using this bracket with the colon in between. And what that’s going to do is, it’sbasically going to create a slice of all the elements of what it’s referring to. So it’sgoing to create a slice of all of the elements of a online 10, we’re creating a slight C,and that’s going to start with a third element of the parent, and copy all the values afterthat. So that’s going to start with the element with index three, which is, of course, thefourth element and every element after that, so this is going to copy four through 10,into the slice at sea, then on line 11, we’re going to do the other syntax, and that’s goingto copy everything up to the sixth element. And that’s the literal sixth element,that’s not element number seven, that’s actually the sixth element, which is going to havethe index five.And then on line 12, we actually see an inner slice. So we’re going to copythe fourth element through the sixth element into our new slice. So let’s go ahead andrun this and see what prints out. So we see the first line printed out is the originalslice that we have. The second line is the copy of that slice that’s copying all of theelements. The third line is going to copy the fourth element on so we see the numberfour through 10. The fourth line copies everything up to the sixth element, so we get the valuesone through six. And then the last line printed out is a slice from three to six. And so we’regonna get the elements four, five, and six printed out. So that can be a little bit confusing,because the first number has a slightly different meaning than the second number. So basically,the first number is inclusive, and the second number is XClusive.So for example, if welook at line 12, again, we’re going to copy from index three, up to but not includingindex six. So that’s another way that you can look at it. Now one thing to keep in mind,remember what I said that all of these operations point at the same underlying data. So if wetake element five, and change that value in the a slice and run this again, notice allof them teams value, because they’re all pointing to the same underlying array. So each oneof these operations includes the fifth index in their results. And each one of those getsupdated to the value of 42.Now another thing to know about these slicing operations isthey can work with slices like we’re doing here, but they can also work with arrays.So if you remember, if I put these three dots in here, it’s actually going to turn a intoan array. And if I run this, we get the same result. And that’s because slicing operationscan have as their source, an array or a slice.So whatever type of data you’re working with,as long as it’s one of those two, you can use these slicing operations. Now the lastway that we have available to us to create a slice is using what’s called the make function.And that’s a built in function that we have to work with. So if I delete all this, anddrop this guy out, we’re going to use the built in make function. And this takes twoor three arguments. So let’s start with two arguments. So the first thing we’re goingto say is the type of object that we want to create.So you can use make for severaldifferent operations. In this case, we’re going to be talking about making slices. Soin this example, here, we’re going to make a slice of integers. The second argument isgoing to be the length of the slice. So in this case, I want to start with three elements.So now let’s just get some information about the slice that we created here. And we’lldo that by dropping in a couple of print statements. So we’ll print out the values of the slice,the length of the slice and the capacity of the slice. So they run this, no big surpriseit zeroed out. So when I create a slice, everything gets set to the zero value, which is whatwe always expect in go to happen every time we initialize a variable, we expect it tobe initialized to zero values.And that’s true for slices just like it’s true for primitives.When we asked for the length, we get a length three, when we ask for the capacity, that’salso set to three. Now we can also pass a third argument to the make function, and that’sgoing to set the capacity. So keep in mind, the slice has an underlying array, and theydon’t have to be equivalent. So if we run this, we see that we’ve created a slice oflength three, it’s got three elements in it, but the underlying array has 100 elementsin it. So why would we do that? Well, the reason is because unlike arrays, slices don’thave to have a fixed size over there and Life, we can actually add elements and remove elementsfrom them.So in order to show you an example of that, let me drop in another example here.And this is going to start with a slice of integers that starts with no elements in it.So if we go ahead and run this, we see what we expect, we see an empty slice length ofzero capacity of zero. Now, if I want to add an element to this slice, I can use the builtin append function. So this takes two or more arguments, the first is going to be the sourceslice that we’re going to be working with. So I’m going to start with a and I’m goingto add an element to it. And in this case, all I want to do is add the number one toit. And then let’s go ahead and print out the value of the slice the length of the sliceand the capacity of the slice again.So if I go ahead and run this, we see that in thesecond operation, we have a value one stored in there, we have the length of one, and noticethe capacity is two. So that’s kind of interesting. What happened here is when we initialize aslice to the value a go assigned a memory location for the slice. And since it didn’thave to store anything, it basically created an underlying array of zero elements for us.As soon as we added an element, obviously, it couldn’t fit in a zero element array. Soit had to assign an array for us. So what go does is it copies all of the existing elements,in this case, nothing to a new array that’s got a larger size. So when we reassigned,it actually did create a new array, this one has a capacity of two, and then it put the value one into thatarray. Now, when we’re dealing with small slices like this, things are pretty cheapand pretty easy, even if you’re resizing the array quite a few times. However, as thingsget very large, these copy operations become very expensive.And that’s why we have thatthree parameter make function. That way, if we know the capacity is going to be somewherearound 100 elements, you can go ahead and start there. And that way, as you’re appendingelements and building up the slicer, you’re not constantly copying the underlying arrayaround. Now, if you remember, when I said the append function can take two or more arguments.The reason for that is this is what’s called a variadic function. So everything after thefirst argument is going to be interpreted as a value to append to the slice passed inthe first argument. So if we have this example, here, we’re actually going to append the values234 and five to the slice returned by A. So if we run this guy, we see that we get theelements one through five created there, and the length is five, like we might expect.But now the capacity is eight knots not fixed in stone, how go resize of the arrays.Butgenerally, what I’ve seen it does is once it fills up the underlying array with a slice,when you add the next element, it’s going to create a new array, and it’s actually goingto double the size from the previous array. So if we start with an empty slice, we seethat the array would initially be of size zero, then we’ll go to 248 1632, and 64 elements.So that’s something else to be aware of, if you’re just over one of those powers of two,you can actually end up with a lot of memory consumed that you’re never going to be using.So again, if you have the ability to come up with a decent first estimate, then that’sgoing to be beneficial to you. Now one common situation that you’re going to run into isif you have a slice of elements, and another slice of elements, and you want to concatenatethem together, so you want to have another slice created that has all of the elementsof the first slice, and all of the elements of the second slice.So you might want todo something like this, if I convert this over to a literal slice, you might want torun a command something like this. Well, this unfortunately, is not going to work. If Igo ahead and run this, you’ll see that we’re going to get go complaining to us. And that’sbecause the second argument to the append function has to have the type of the slice.So go can only accept integers here. It can’t accept a slice of integers.But we do havea way around this. So I don’t know what it’s called an NGO in JavaScript, they would callthis the spread operator, where if you have three dots after the slice, it’s actuallygoing to spread that slice out into individual arguments. So if we run this, this is goingto work. And it works exactly the same as if this weren’t a slice at all, it’s basicallygoing to take this slice and decompose it into looking something like this. So thesework exactly the same way. But it’s a convenient feature to know about if you have slices andyou want to concatenate them together. Now, some other common operations that you mightdo with slices are stack operations. So let’s just say that we’re treating our slices astack, and we want to be able to push elements onto the stack and pop elements off of thestack.And things like that, with the append function is going to allow us to push elementsonto the stack. But how do we pop elements off? Well, we have a couple of different waysthat we want to do this. If we want to do what’s called a shift operation, which meanswe want to remove the first element from the slice, then we can do this operation here.And what this is going to do is it’s going to create a new slice that starts at indexone, which has the value two in this example, and takes everything else from that. So ifwe go ahead and print out the value of b, we’ll see that that has the elements two throughfive. Now if you want to trim an element off of the end, then you’re going to have to usea different syntax here.So we want all of the initial elements. So we’re going to startwith a colon, and then we’ll use that length operation, figure out the length of the slice.But remember, that’s going to return the number that’s too large, we actually want to removean element off. So let’s go ahead and do length minus one. And this will have the values onethrough four in it. So it’s pretty easy to remove an element from the beginning of theslice or the end of the slice.But what happens if you want to remove an element from themiddle? Well, here, things get a little bit hairy.Because what we have to do is we actually have to concatenate two slices together, thefirst slice is going to be all the elements up to where we want to remove the element.So in this case, we can take the first two elements, by doing a slice of a, and passingin colon two for this slice that we want to create, then we have to concatenate to thatall of the element after the index we want to remove. So in this case, we’re removingthat middle element. So we’ll take from three on and then we have to use this spread operationin order to spread things out so that the append function is happy.So let’s go aheadand run this and then get my syntax correct here. And now we see that we’ve got the elements124, and five. So we’ve successfully removed an element from the slice, they have to bea little bit careful here. because keep in mind, we’re working with references to thesame underlying array. Because these are all slicing operations, there’s one underlyingarray and everything is being done on that underlying array. So just to show you thehavoc that we’ve created here, let me go ahead and print the value of a out here, and thenprint the value of a out afterwards and go ahead and run that. And you see we start outwith the elements 12345. Like we might expect, we do our slicing operation, removing theelements from the middle, we get 1245, which was what we might expect. But then when weprint a out, things look a little weird, because we have that slice that V represents whichis 1245, our three is completely gone, and five is duplicated.So this is something tobe very sensitive about. If you’re going to be removing elements from the inside of aslice using a command like we have on line 10, make sure that you don’t have any otherreferences to that underlying array. Otherwise, you’re going to get some unexpected behavior.So what do you do if you have a situation like this, and you really, really need a tostay the same, and you really, really need B to change? Well, unfortunately, we don’thave the tools to work with this right now. Because what we’re going to need to do isto use a loop to create a copy of that slice that doesn’t point to the same underlyingarray, and then you can make the manipulation.So when we get to the looping section, we’llshow you how to do loops. And then you’ll have all the tools that you need in orderto handle that situation. For now, the only thing I can say is be aware of this behavior.And if you get into a situation like this, understand that you’re going to have to doa little bit of research in order to make sure that your application responds correctly.Okay, so that covers what I want to talk about with the raising of slices. Let’s head intoa summary and review what we’ve talked about. arrays and slices are very common in NGO applications.And I think you’re going to see them all over the place as you start to work more and morewith the language. So I hope that this conversation has really helped you understand what arraysand slices are and some basics about how you can work with them. We started our discussionby talking about arrays. And we learned how there are collections of items with the sametype.So you can’t create an array that has strings and integers and things like thatall of the types have to be the same, but does collect them all together. And as westart to get into conversations about looping and things like that, we’re going to findhow we get some very powerful tools that we can work with, when we’re basing our dataon arrays and slices. They are fixed size. So when you create an array, you have to specifyat compile time how big that array is. And it can never change. So you can’t make themsmaller, and you can’t make them larger. There are three different ways that we can declarean array, we can do the literal style, like you see on this first line, where we’re goingto specify the number of elements and then we use a literal that’s going to initializethose elements.However, we do have a shorthand notation that uses three dots instead of thatfirst size. And that’s going to be a little bit more robust in your application design.Because if you run into a situation where you need to add another literal, you don’thave to remember to update the size of the array, it’s going to update automatically.We also have this third syntax where we can declare a zero data array. In this case, we’regoing to declare an array of three integers, each one of those integers is going to startwith the value zero. We also talked about how arrays are zero based. So we’re goingto be counting from the head of the array. So the first element in the array has theindex zero, the second element has the index one, and so on. So in this example, if weasked for the index one of array, we’re going to get the value three out, we have the Lenfunction that’s going to return the size of the array in case you need to know that someother place in your application.And you want to have a way to be able to handle that robustly.That’s not relying on the fact that you know, at design time how big that array is, youcan use the Le n function to interrogate the size of the array. Anytime you’re moving thearray around, it’s going to copy the underlying data. So if you have a three element array,and you assign that to another variable, all three elements are going to be copied to anew location in memory and you’re going to be working with an independent copy. So thatcan cause some unexpected behaviors because if you change that copied array unexpectedchanges to be reflected back in the initial array, that won’t happen. And it can be veryexpensive because all that memory has to be allocated a second time. Then we moved on to discuss slices and howthey’re very similar to arrays. As a matter of fact, they’re backed by an array.So everyslice that you see, under the covers, go has an array that’s holding all of that data foryou. There are several creation styles, we saw that we can create a slice by slicingan existing array or another slice, we have the literal style that we can use, which isvery similar to the array literal, except for we just leave those three dots out, becausethe size of the slice is dynamic. And so it can be determined at runtime, we also sawhow we can use the make function.So if we pass two arguments to the make function, thefirst is going to be the type of slice that we want to create. So in this example, we’regoing to create a slice of integers. And the second parameter is going to determine thelength and the initial capacity of the slice. If we need a capacity that’s different thanthe initial length, then we can pass a third parameter into the make function.And that’sgoing to allow us to specify a capacity independent of that initial length, the Len function returnsthe length of the slice itself, whereas the capacity function returns the length of theunderlying array. So if for some example, you want to control the resizing of the slice,you can go ahead and do that. And use that capacity to function to understand when you’restarting to get to your limits, you can also use the append function to add an elementto the slice. And what that’s going to do is it’s going to take in a parent slice, andit’s going to take in one or more elements to add to that slice. Now through the courseof that append operation, you can add elements that exceeds the capacity of the underlyingarray. If that happens, then you are going to trigger a copy operation. And all of thoseelements are going to have to be copied to a new location. So be aware of that. If you’redealing with large slices of data, and you end up resizing, a lot of times your applicationperformance can suffer, you might want to think about using that three parameter makefunction, in order to set the capacity of the slice close to where you need it to be.When you’re passing slices around in your application.Keep in mind that assigning anew value to an existing slice actually points to the same underlying array. So if you manipulatethe slice in one location, it’s actually going to affect all the other slices that are pointingto that same underlying data. So we talked about an example where we created a sliceand removed the middle element out of it. And we saw how that actually affected theinitial slice, and could cause some behavior that we weren’t expecting. I want to completethe discussion, I started in the last video by talking about the two remaining collectiontypes that are available and go. And those types are mapped in structs. So we’ll startour discussion by talking about maps, we’ll talk about what they are, how we can createthem, and then how we can manipulate the data within the maps, then we’ll move on to thestruct data type, we’ll talk about what they are, how we can create them, then we’ll moveon to the naming conventions that we’re going to have to be aware of as we’re working withstructs, then we’ll talk about a concept called embedding, and how we can use that to havea struct that we’re creating inherit a lot of functionality from a base struct, thenwe’ll finish our discussion of structs by talking about a concept called tags, and howwe can use tags to provide some additional information about the fields within our structsto help the consumers of objects created from the struct get additional information abouthow that field is intended to be used.Okay, so let’s begin our discussion by talking aboutwhat maps are and how we can use them. So the first thing that we’re going to need toget our heads around when we’re talking about maps is what exactly a map is. And I thinkthe easiest way to show you what a map is, is by showing you a map. So we have an examplehere of a variable called state populations. And this represents a map of US state namesover to the population within those states. So what we see here is a map is going to takesome kind of a key, in this case, the state names, and it’s going to map that over tosome kind of a value, in this case, the population of that state.So what this provides us isa very flexible data type. When we’re trying to map one key type over to one value type. Now there’s a couple of constraints we’regoing to have to keep in mind. As you can see up in the Declaration on line eight, we’regoing to map one key type to one value type. So all of the keys in this map have to beof type string, and all of the values have to be of type integer. Now we can use a lotof different types for the keys. And we can use any type for the value. But when we declarea map, that type has to be consistent for every key value pair within the map.So ifwe run this, we can see an example of what a map looks like when we print it. And it’snot the best output in the world, but we can get an idea of what’s going on. So we seethat we get the key value pairs printed out. So we get California, Texas, Florida, NewYork, Pennsylvania, Illinois, and Ohio. So one thing that I just alluded to is that wehave a lot of options with the key type, but we don’t have an infinite number of options.So the basic constraint on the keys when you’re creating a map is they have to be able tobe tested for equality.Now most of the types that we’re working with can do that. So Booleancan be tested for equality, all of the numeric types, strings, pointers, interfaces, structsarrays, and this thing we haven’t talked about called channels. All of those can be testedto see if one instance of for example For a string variable is equivalent to anotherone. However, there are some data types that cannot be used for equivalency checking. Andthose are slices, maps and other functions. So for example, if we create a map calledm, and we’ll make that a map of, say we want to map slices of integers over two strings.And we’ll use the literal syntax for that, and then we print that out, then you wouldexpect a map to print out. But in fact, we get an error because we’ve got an invalidkey type because a slice cannot be a key to a map. However, if we had an index here, thenit turns it into an array.And now we do get a successful printout, of course, the mapis empty. So we don’t see anything, we just see this empty map right here. But we weresuccessfully able to create the map, because an array is a valid key type, but a sliceis not. So what are the different ways that we can create a map? Well, you see, the firstway here, this is the literal syntax, and this is going to probably be the most commonway you’re going to see maps created.So we just need to declare the type of map. Andwe’re going to do that using this syntax that we see here on line eight, where we’re goingto start with the map keyword in square brackets, we’re going to list the type of the key, andthen after the square brackets, we’re going to list the type of the value. Another waythat we can do this is we can use the built in make function again. Now we first saw themake function when we were talking about slices. But we can use that once again here. So ifI copy this variable up here, and I set this equal to the result of calling the make function,and we’re going to tell it what type of map we want to make. So we’re going to use themap keyword again, the key is type string, the value is type integer. And now we cango ahead and remove this colon.And if we run this, we have to remove our m again fromour print statement. Now if we run it, we get the same value printed out. So this isa common way that you can work with maps, if you don’t have at the time that you’redeclaring the variable, the entries that you’re going to want to put in it. So for example,if you’re populating the map within a loop, you might use this syntax. Now another optionthat you have with the make is it will take a second parameter. So if I run that likethis, then that works. However, I wasn’t able to find the intention for this. So this isavailable. But it doesn’t seem to affect the length of the map that’s created, the mapis always going to be the length of the number of elements in it, but it might have someeffect under the covers. If you find that what that’s for, please leave a comment downbelow.So that I can learn along with you know, let me go ahead and remove this becauseI don’t know what it’s there for. And I haven’t seen that very commonly used and run thisagain. And we can see that we’re back to where our map used to be. Now how are we going tomanipulate the values in our map? Well, the first thing that we can do is we can pullout one single value from the map by using the square brackets and typing in the valueof the key. So the key can be provided either as a variable or as I’m doing here as a literal.So if I go ahead and run this, we see that we get the population of Ohio is 11 point6 million people. So we can interrogate the values of our map. Using this syntax here.We can also add a value to our map using a very similar syntax. So we call on the statepopulations variable.And I add a key. In this case, let me add the next largest state,which is Georgia. And it as of 2016, had a population of 10,310,371. Now I can pull thatvalue back out, run this. And we see that we get that value printed out of our map.If we print the entire map out, we see right here, Georgia gets added in here. Now, somethingyou might have noticed, let me do this, I’m going to copy this print line here, put itabove where we added the Georgia key. And notice the ordering is different. And thisis going to be a very important thing to keep in mind as you’re iterating through maps lateron, the return order of a map is not guaranteed.So even though we declared California, Texas, Florida, New York, Pennsylvania, Illinois,Ohio, and then added Georgia, this is not like a slice, a slice or an array would returnthose elements in exactly the same order we provided them.In a map, everything is storedin a way that cannot guarantee the order upon returning. So even though we just added oneentry here, it completely changed how everything was organized within the map, and we get ita little bit different output. Now another thing that I want to show you is that we candelete entries from the map.So we can do that using the built in delete function. Thefirst is the map that we want to delete from, and then we need to provide the key that wewant to delete. So if we go ahead and delete Georgia back out, it wasn’t there very long.But if we run it looks like I need to add my s here. Now if we run it, we see that gais no longer part of our map. So we can add by just calling on the map providing a newkey and value. We can delete using the built in delete function, and we can interrogatea value from the map using those square brackets.Now, an interesting thing about deleting isif I asked for the value of that key again, what do you think I’m going to get? So wesee here in the output, Georgia is no longer part of the map. So you might expect somesort of error to be raised. Well, in fact, if I run this We get the value zero out. Nowthat should cause you some concern, because does Georgia have a population of zero? Oris it missing from our map? Did I just misspell the key? What’s going on? So for example,if I fat finger, Ohio, and I forget the I and run this, I get a value zero.Well, dideverybody move out of Ohio? What happened? What with what we know right now, there’sno way for us to really now. So there’s another way that we can interrogate our map. And thatis using what’s called the comma. Okay, syntax. So with doing what we know, right now, we’rebasically doing this, we’re calling state populations. And we’re asking for the key,Ohio, and I’ll continue that misspelling.And then we’re printing out the value of thatpopulation variable, and we get the value zero. Well, we can also add an optional comma,okay, here. And when we do this, let’s go ahead and add that okay, variable to the outputand see what that’s going to do. So notice that this prints out the value false. So theokay is false if the key was not found within our map, but if we add the eye back in andcorrect our spelling, we see that we get the value true out. So if you’re in a situationwhere you’re not sure if the key is in the map or not, then you can use this comma, okay,syntax. As a matter of fact, if you just want to check for presence, then we can use thatright on the operator again, in order to throw away the actual value.And then we just getthe okay variable printed back out. Now, there’s nothing magic about the variable name, okay.But it is conventional to use, okay, and you go programs when you’re using it for thiskind of a test. The next thing that I want to show you about maps is we can in fact,find out how many elements are in them. So we can do that using the built in Le n function.So if I go ahead and run that, we see that we get the value seven, and we have let’ssee 12345 yet we have got seven states declared in our map right now. So if we added anotherstate back in, then the length function would return eight. The other thing that’s interestingto know is that just like slices, when you have multiple assignments to a map, whichis especially important when you’re passing maps into functions, the underlying data ispassed by reference, which means manipulating one variable that points to a map is goingto have an impact on the other one, so I can demonstrate that by creating another variablecalled SP, and set that equal to state populations.And then let’s go ahead and delete poor Ohioout of SP, it always seems to get left out. And then we can print out SP and print outstate populations. So if I run this, we see that in our first result, we don’t have theentry Ohio anymore. And then our second print statement, which is the original map,Ohio has been removed from there as well. So if you start passing maps around and youstart manipulating the data within that map, keep in mind, you can have side effects onthe calling functions or any other place where that map is referred to. Because manipulatingthe map in one place is going to have impacts on every other place to use. So the finalcollection type that I want to talk about today is called a struct. Now at first, youmight not think of a struct as a collection type. But go with me on this, if I drop inan example, we see here an example of a struct.Now I’m in kind of a doctor who frame of mindtoday. So we’re going to run with an example that’s talking about some information aboutone of the doctors from Doctor Who. So if I go ahead and run this, we can see that we’regetting information on the third doctor, the actor’s name is john Pertwee, we see someof his companions listed out here. So the reason I call this a collection type is lookat the declaration or the struck on line seven through 11. What we have here is a list offield names. So we’ve got number, actor name and companions as field names, and then atype associated with that field. So the doctor number is an integer, the actor name is astring, and the companions is a slice of strings. So what the struct type does is it gathersinformation together that are related to one concept, in this case, a doctor. And it doesit in a very flexible way.Because we don’t have to have any constraints on the typesof data that’s contained within our struct, we can mix any type of data together. Andthat is the true power of a struct. Because all of the other collection types we’ve talkedabout have had to have consistent types. So arrays always have to store the same typeof data slices have the same constraint. And we just talked about maps and how their keysalways have to have the same type. And their values always have to have the same type withinthe same map. When a struct we can have our fields describe any type of data that we want.So we can have structs that contain other structs, anything that we want. So while ina lot of ways, structs are the simplest type of collection that we’re going to be talkingabout. They’re also one of the most powerful. So we see down here in the main function,how we can create a struct and I’m using the declaration syntax, where I’m using namedfields.So we’re going to create a variable called a doctor. And we’re going to use thisliteral syntax. So we list the type of the struct doctor, we use the curly braces likewe do with every other literal definition. And then I have a list of the field namescolon and the value. So number colon three after name colon, john Pertwee, and then campaignTo set equal to this slice of strings now notice that when I’m setting something equalto a slice, I do actually have to tell go, what kind of collection type, I’m initializingfor that, and then down here on line 23, I go ahead and print the entire value of thestruct out. And you see that I get the values printed out, I see three, john Pertwee, andthen the three companions that john Pertwee had, in his time as the doctor.Now if wewant to interrogate one value from a struct, then we’re going to use what’s called thedot syntax. So if we ask for the actor name of this struct, then we’re going to put adot after the variable name, put in the field name. And when we run this, we see that weget john Pertwee out. So we can work with the struct as a whole, or we can start drillingdown. As a matter of fact, we can drill down through the structure. So if we ask for thecompanions, we can get that out, certainly. But this is a slice like any other slice.So if I just want the second item in the collection, I can get Joe grant out by interrogating theslice that gets returned by asking for the companions field. Now another way that wecan instantiate our struct is using what’s called a positional syntax. So here, I’m listingthe field names, but it don’t have to.So if I go ahead and take these out, and takethis out, so I print the entire struct out, then I get exactly the same result as I gotthe first time. Now, this is valid go syntax, I would encourage you not to use it, though.And the reason for that is it can become a maintenance problem. So for example, let’sjust say that this is our struct, and this is checked into source control, and everybody’shappy with it. But then let’s say we have a change request Comm. And we’re going toadd a list of the episodes that each doctor appeared in. So that’s going to be anotherslice of strings. And that gets added right here. Well, if we use the positional syntax andtry and run this, we’ve got a problem.Because go doesn’t know how to map the fields thatwe provided into the initializer. Because there’s three values provided in the initializer.And there’s four values in the struct. So we have to find every place that we have oneof these declared with the positional syntax. And we have to add, for example, a placeholderor populated or something. So we go ahead and run this and everything’s working again.But now, what happens if another change comes along, and somebody does this? Now they’vechanged the order of the fields. When we run this, everything looks fine. But when I askedfor the doctor’s companions, again, I get an empty slice, because the positional syntaxrequires the fields to be declared in the correct order, much better for us to go aheadand add in the field names. So let me drop those in real fast here. Now when I run this,I get the expected results out.And notice what the field names syntax, I don’t evenhave to have it in the same order as they’re declared in the struct go is going to figureout how to map the data from the initializer over into the object that’s created by usingthose field names. The other advantage that I have is, if I don’t have any informationabout the episodes at this point in my program, I actually can ignore the fact that that fieldexists. And what this means is I changed the underlying struct without changing the usageat all, which makes my application a little bit more robust and change proof. So whileit is possible for you to use the positional syntax, I would strongly recommend you donot use it unless you’ve got a very short lived struct. We’ll talk about anonymous structshere in a second. And in those situations, positional declaration might make sense becausethat struct is not going to live for very long. However, I would strongly recommendanytime you’re taking the time to declare a type, like we’re doing here on line seven,then you’re generally going to be better served by using field names explicitly instead ofthe positional syntax.Okay, the next thing I want to talk about are naming conventions.So as you can see, here, I’ve got my type declared as Doctor with a capital D, and thefields declared as lowercase. So the rules in this situation, follow the rules for anyother variable and go, if we start with a capital letter, it’s going to be exportedfrom the package. If we start with a lowercase letter, it’s going to be internal to the package.So in this case, I can work with all of the fields, because I’m declaring the doctor typein my main package. And so my main function, which is also in the main package has accessto it. However, nothing in any other package would have access to this. So it would beable to see that there is a doctor struct, but it wouldn’t see any field names.So ifI did want to publish these out, so anything can use them, I would have to go ahead andcapitalize these field names, of course, or have to capitalize them in my declarationas well. And then when I run I get the exact same result that I got before. So I forgotto change this variable as well go ahead and run that, and I get the expected result out.So generally, we’re going to follow the same convention as we do with any other variable.uppercase is going to export lowercase is going to import, you should use Pascal casingand camel casing, you shouldn’t have underscores and things like that in your field names orin your struct names.Now if you notice here on line seven, I have explicitly created atype called a struct. And that’s going to be a very common way that you’re going tosee struct to use. You see you’re going to define a type and then everywhere you needto use that struct, you can just refer to it by its type. But we don’t have to do that.And there are some situations where you might see a program like this.So on line eight,we’re declaring what’s called an anonymous struct. So instead of setting up a type, andsaying, doctor, and that’s going to be a struct, and that’s going to have a single field calledname, that’s going to take a string. We’re condensing all of that into this single declarationright here. Now, I can’t use this anywhere else, because it’s anonymous. And so it doesn’thave an independent name that I can refer to it. But I can certainly use this just fine.So let me go ahead and delete this. And then notice I’m using the initializer syntax righthere. So we got two sets of curly braces, it’s very important to remember what eachone is doing. So the first set of curly braces is paired to the struct keyword. And it’sdefining the structure of the struct. The second is the initializer. And it’s what’sgoing to provide data into the struct. So if we run this application, we see that wedo get the struct with the value john Pertwee printed out and everything’s gonna work justfine.Now, when are you going to use this, this is going to be used in relatively fewsituations, basically, you’re going to use this in situations where you need to structuresome data in a way that you don’t have in a formal type. But it’s normally only goingto be very short lived. So you can think about if you have a data model that’s coming backin a web application, and you need to send a projection or a subset of that data downto the client, you could create an anonymous struct in order to organize that information. So you don’t have to create a formal typethat’s going to be available throughout your package for something that might be used onlyone time. Now, unlike maps, structs are value types.So if I take this example here, and let’s just use the same basic manipulation thatwe’ve been doing with all of these collections, so I’m going to create another struct, andI’m going to assign it to the value of my current struct, and then I’m going to manipulatethe value of that name field.So I’m going to create another doctor called Tom Baker.And then let’s see what happens when we print both of these doctors out. So as you can see,even though I copied another doctor from a doctor, and change the value, the values remainindependent. So a doctor still has the name john Pertwee, another doctor has the nameTom Baker. So unlike maps, and slices, these are referring to independent datasets. Sowhen you pass a struct around in your application, you’re actually passing copies of the samedata around. So if you’ve got structs, that are very, very large, keep in mind, you’recreating a copy every time you’re manipulating this. Now, just like with arrays, if we dowant to point to the same underlying data, we can use that address of operator. And whenwe run this, we have in fact, both variables pointing to the same underlying data. A doctoris the struct itself.Another doctor is a pointer to the struct. So when we manipulateits name field, we’re actually manipulating the Name field of the a doctor struct. Thenext thing that I want to talk to you about in go is a concept called embedding. Now,you may have heard in your research on the go language that go doesn’t support traditionalobject oriented principles. So for example, we don’t have inheritance, and oh, my goodness,how am I going to create my program if I don’t have inheritance available? Well, let me showyou what go has, instead of an inheritance model. It uses a model that’s similar to inheritancecalled composition.So where inheritance is trying to establish the is a relationship.So if we take this example here, if we were in a traditional object oriented language,we wouldn’t want to say that a bird is an animal, and therefore a bird has a name abird has an origin, a bird has also bird things like its speed, and if it can fly or not,go doesn’t support that model. But instead, it supports composition through what’s calledembedding. So right now we see that animal and bird are definitely independent structs,there’s no relationship between them. However, I can say that a bird has animal like characteristicsby embedding an animal struct in here like this.So I’ve just embedded the struct itself,I haven’t provided a name. Now, if I did something like this, then how to have a named fieldin the bird called animal. But I’m not doing that I’m doing this. So I’m just saying embedthe animal struct right into the bird struct. Now how can I use this? Well, let me dropin a new main function here. And then you can see, so I’m creating an instance of abird.And then I’m initializing the variables. So name is going to be E mu origin is goingto be Australia, the speed is 48 kilometers an hour, and it cannot fly. So if I printthis out, I see that other than a little bit of a strange syntax with that inner type,I see that I have all of my fields defined, it’s a matter of fact, I can come in hereand dig into any one of those animal fields. And everything worked exactly like I wouldexpect them to so it kind of looks like bird is inheriting the properties of animal. Butreally what’s happening here is there’s some syntactic sugar go is handling the delegationof the request for the Name field automatically to the embedded animal type for you.So ifyou try and pass these around and look to see if the bird is a type of animal, it isnot bird is still an issue. Independent struct that has no relationship to an animal otherthan the fact that it embeds it. So it’s not a traditional inheritance relationship wherea bird is an animal. Instead, it’s a composition relationship, which is answering the questionhas a, so a bird has an animal, or has animal like characteristics is how we would say itin this example. But it is not the same thing as an animal, they cannot be used interchangeably.In order to use data interchangeably, we’re going to have to use something called interfaces,which we’ll talk about a little bit later. Now we can see in this example, that if wedeclare the type, and we initialize the variables afterward, everything’s pretty clear, we canjust treat all of the fields as if they’re owned by the bird struct. And we don’t haveto worry about the internal structure of the struct. And that’s very intentional.However,if we’re going to use the literal syntax, we do have to know a little bit about thebirds internal structure. So let me drop in this code here, clean up our formatting alittle bit, and then remove these lines here. So this is declaring exactly the same object,we’re going to have an E mu from Australia, the speed is actually going to be 48 kilometersan hour, and can fly is going to be false. But notice what I have to do here, I haveto explicitly talk about the internal animal struct.So when I’m working with the literalsyntax, I have to be aware that I’m using embedding. But if I just declare the objectand manipulate it from the outside, I don’t have to be aware of it at all. Now, when shouldyou use embedding? Well, I will say Generally, if you’re talking about modeling behavior,embedding is not the right choice for you to use. When we get into methods, we willsee that embedding will allow behaviors or methods to carry through into the type thathas the embedding. However, the fact that we can’t use them interchangeably, is a verysevere limitation. Generally, it’s much better to use interfaces when you want to describecommon behavior. So when is embedding a good idea? Well, if you’re offering a library,for example, and let’s just say you’re making a web framework, and you’ve got a very sophisticatedbase controller, in that case, you might want to use consumers of your library to embedthat base controller into their custom controllers, so that they can get useful functionalityout of it.In that case, you’re not talking about polymorphism. And the ability to interchangeablyuse objects, you’re just trying to get some base behavior into a custom type. And in thatcase, embedding makes sense. The last thing that I want to talk about with structs isa concept called tags. So let me just drop in another example program here that we canwork with. This is a simpler version of what we had before, because we don’t need to structsfor this conversation.So we’re just going to have a simple animal struct with the nameof the origin fields. And then what I want to do is I want to add what’s called a tagin order to describe some specific information about this name field. So let’s say for example,that I’m working with some validation framework. So let’s just say that I’m working withina web application, and the user is filling out a form and two of the fields are providingthe name and the origin. And I want to make sure that the name is required and doesn’texceed a maximum length. So I can do that with a tag that looks something like this.So the format of a tag is to have backticks as the delimiters of the tag, and then wehave these space delimited key value pairs. So my first field is going to be required.So I’m going to say that the Name field is required. And then I’ve got a max length argument,which in this case, is set to 100 characters.So the value of the tag is arbitrary, youcould actually put any string that you want in here, but this is the conventional usewithin go, we’re going to use space delimited sub tags. And then if you do need a key valuerelationship, then you’re going to use a colon to separate the key and the value. And thenthe value is typically put in quotation marks. So now that we have this, how do we get atit? Well, the way that we’re going to get at it is using gos reflection package.Sothere’s no straightforward way from an object to get at the tags of a field, you have touse reflection in order to get that, unfortunately, go makes this pretty easy. So the first thingthat I need to do is I need to get the type of an object that I’m working with. So I getthat using the reflect packages type of function. And I have to pass in an object to this. SoI will just initialize an empty animal to get them that and then I can grab a fieldfrom that type, using the types field by name method, and then passing in the name. In thiscase, I want the name name. And now I can get at the tag by asking for the tag propertyof the field. So if I run this, we see that I do in fact, get that tag out.Now, whatdo I do with that? Well, that’s really up to my validation framework to figure out alltags do is provide a string of text and something else has to figure out what to do with that.So this tags value is meaningless to go itself, we’re then going to have to have some sortof a validation library that’s going to have to parse this figure out that yes, requiredis part of the tag. And then it’s going to have to decide well, if required is thereand then I’m going to apply this logic making sure the string is non empty or whatever makessense in our use case. Okay, so that finishes up what I have to talk about with maps andstructs. Let’s go into a summary and review what we’ve talked about.In this video wetalked about the two remaining collections types that are available and go, we talkedabout maps, and we talked about structs. And when we talked about maps, we learned thatthey are collections of value types that can be accessed by keys, they can be created asliterals, or via the make function, and members are accessed via the square bracket key syntax,we can check for the presence of an element within a map using this comma, okay syntax.So we can ask for the value at a comma, okay, and what the map is going to return is thevalue type as well as a Boolean, that’s going to indicate if the value was found or not.Now, if the value wasn’t found, your value variable is going to be the zero value ofthe value type in that map. So for example, if you’ve got a map of strings to strings,and the element isn’t found, you’re going to get an empty string returned out, if you’vegot a map of string to integers, for example, you’re going to get the value zero.If youhave multiple assignments to the same map, they all point to the same underlying data.So they’re what are called reference types, which means that if you manipulate the datain a map in one location, any other variables that are pointing to that same map are goingto see that change as well. We then went on to talk about the struct type, and how they’rea collection of disparate data types. So whereas arrays and slices and maps are all collectingthe same data type together, a struct is unique in that it collects any type of data together.So you’ve got a common field name. But those fields can point to any valid data structurewithin go. They’re keyed by name fields, which generally follow the syntax of any valid variable,including whether they export it or not. So if you capitalize the name of the field, thenthat’s going to be exported from the package. If you leave it lowercase, then that’s goingto be kept internal to the package. They’re normally created as types. But we can createanonymous structs if we need to.And again, common use cases for this are very short livedstructs, such as generating a JSON response to a web service call, that’s only used onetime. structs are value types. So if I assign a variable to an existing struct, then allof the struct values are going to be copied over to create a brand new struct. So if Imanipulate a struct in one location, it’s not going to affect any other variables inyour application. We don’t have an inheritance system within go.But we can use compositionusing what’s called embedding. So when we want to embed one struct within another, wejust list the type of the struct, and we don’t give it a field name. Go is then going toautomatically interpret that for us and delegate any calls for fields or methods in the containingstruct down to the embedded struct. If that top level struct doesn’t contain a memberwith that name, we also learned a little bit about tags and howthey can be added to struct fields to describe that field in some way. So there’s a lot ofdifferent use cases. For this. The JSON package uses this to provide ways to map field namesfrom NGO field names, which are typically uppercase to follow JSON conventions, whichare typically lowercase. We also saw that we can use this, for example, to pass informationinto a validation framework.And that framework could generate errors. If we need fields tobe required, or have rules about their length or things like that, I want to start a discussionabout the tools that go makes available to control the flow of execution in our applications.In today’s video, we’re going to focus on two of these tools, the if statement and theswitch statement. We’ll start a discussion by talking about if statements. And we’lltalk about all of the different ways that we can use them in our applications. And we’regoing to specifically focus on the various operators that are often associated with workingwith if statements. And we’ll go through what those are and how you can use them. And thenwe’ll talk about the relatives of the if statement. And those are the if else statement. And theif else if statement. We’ll then move on to talk about switch statements. And we’ll startthat conversation with some simple use cases for switch statements. We’ll then talk aboutcases with multiple tests, how we can follow through from one case to another in our switchstatements.And then we’ll talk about this special version of a switch called a typeswitch. So let’s go ahead and jump in and start learning about if statements. In orderto start our discussion about if statements, I want to start as simply as we can. So ifyou look at this application here, it’s got just about the simplest if statement thatI could come up with. So we’re going to start with the if keyword as you see here on lineeight. And then we’re going to have an expression that generates some kind of a Boolean result.And that’s actually where we’re gonna spend a lot of time when we’re talking about ifstatements is how to generate these Boolean results. In this case, I’m just using theliteral true, which is the simplest Boolean result that we can come up with.And theninside of these curly braces here, I’ve got the code that’s going to execute if that Booleantest returns true. So in this case, since we’re using a literal true, then the testis always going to pass. And when I run this application, I see that I get this test istrue printed out in the results here, if I change this to a literal false, and we seethat we don’t get any output from the application because the code inside of the curly bracesis not executed.Now, one thing to keep in mind if you’re coming to go from another language,is you may be expecting this to be valid syntax. Well, if we try and run this, we actuallyare going to get a syntax error because one of the design decisions that was made withgo is that You’re never allowed to have a single line block evaluated as the resultof an if statement.So you always have to use curly braces, even if you only have oneline to execute. Now, this style of this statement has the Boolean test right here. And that’sthe only thing after the if clause. There’s actually another style that’s very commonlyused in the go language. And that’s what I would call the initializer syntax. So as yousee here on line 17, we’ve got a call into a map that’s pulling out the value from amap, and it’s pulling out the okay variable.And then notice I’ve got this semi colon,and then the Boolean result listed here. So this part here, this first part of the ifstatement, is the initializer. So the initializer allows us to run a statement and generatesome information that’s going to set us up to work within the F block. So in this case,I’m generating a Boolean result by interrogating the map.And then I’m using that as the testto see if the code inside the if block should execute or not, I also have access to thepop variable that I’m creating right here inside of the F test, and that variable isgoing to be scoped to the block. So if I execute this, you see that I get the population ofFlorida printed out, no problem there. If I try and work with that variable outsideof here, and printed out again, I’m going to get an undefined error, because the popof variables is only defined within the scope of that if statement. The next thing thatI want to talk about with if statements are the comparison operators that we have. I mean,obviously, as long as we can generate pure Boolean values, things are going to be prettysimple.But that’s a pretty limited benefit, because in a lot of applications, we needto do some kind of a comparison in order to determine if the branch should execute ornot. So let me drop in this example here. And let’s just say that we’re building somekind of a number guessing game. Now to keep things as simple as possible. This is goingto be a pretty simple number guessing game, because we’re going to hard code the valuethat we’re going to guess. And we’re going to hard code our guests. So we’re not goingto have a user interface involved here at all. And we’re not going to randomly generatethe number that way, it’s very clear what the application is doing. So right now whatwe have is we’ve got the number that we’re going to try and guess we’ve got our guestshere on line nine. And then we’ve got a couple of tests. So in line 10, we’re checking tosee if the guess is less than the numbers.So this is the first comparison operator thatwe’re looking at. This is the less than operator, we also have the greater than operator andthe equality operator. So if we run this with the guests of 30, and a number of 50, we’regoing to get the value to low printed out because this first test evaluates to true.And the second and third test evaluate to false. If I change my guest to 70, and run,then the second test evaluates to true and the first and third evaluate to false. Andas you might expect, if I put in a guess of 50, and run this, then I finally got it. Sothis is the basics of a number guessing game, all you need to do is wrap this in loops,which we’ll talk about in a future video and add a little bit of a user interface and you’vegot your first game written in the go language. Now there’s some other operators that we haveavailable.And it’s a little hard to justify getting them into this example. So I’m justgoing to go ahead and dump them here. And then we can take a look at them. So this firsttest is called the less than or equal operator. So it’s going to check to see if number isless than or equal to guess the second is the greater than or equal to operator. Andthe third is the not equal operator. So if I go ahead and run this, you see that we areless than or equal to because we’re exactly on the number we are also greater than orequal to, and we fail the non equal t test. So we get true true false printed here, ifwe go with 30. Again, we’re going to get false true true. And if we go with 70, we’re goingto get true false true. So these are the six different comparison operators that you’retypically going to use in your applications. And these work with all numeric types. Theydon’t however, work with things like string types.So if you’re going to work with stringtypes, typically what you’re going to work with is the equality operator or the non equalityoperator. And that goes for any kind of reference type as well. Now the next thing that I wantto do in this example is add in some kind of simple validation. So if you imagine thatwe’ve got some kind of a simple user interface where the user is asked to enter a numberon the keyboard, and then we’re going to use that as our guests, then we’re going to needsome way to validate that number to make sure that for example, they don’t enter negativefive.So to do that, we can add another logical test. But we can also combine multiple teststogether using what are called logical operators. So let me drop this code in here. And youcan see our first logical operator. So this code here is conducting two tests, it’s checkingto see if the guest is less than one. Or if the guest is greater than 100. And if it is,then we’re going to print out a message here, we can also put a guard around our actualgame code, checking to see if the guess is greater than or equal to one. And this isthe AND operator less than or equal to 100. So this first test case is going to executeif the guess is out of range. So if we enter negative five, for example, then we’re goingto run this and we see that the guests must be within one and 100. If we enter a numberthat’s within range, then everything executes like we expect it to and this code on line11,000 execute. So this first operator here is called the OR operator. And this is checkingto see if the test on the left is true, or the test on the right is true.So obviously,we can’t have the guest less than one and greater than 100 at the same time, but oneor the other could be true. And if one of those is true, then we’re going to have aninvalid guess. And it makes sense to print out a message to the user saying that thisother operator that we see here is called the AND operator. And it evaluates to trueif both the test on the left and the test on the right evaluate to true. So if we hada guest, for example of 105, then this code is gonna evaluate to true because it is greaterthan or equal to one. But this code is not because 105 is not less than or equal to 100.So with an and test, both cases have to be true, unlike an or test, we’re only one ofthe two has to be true.So a guess of 105 is going to print out our error message. Andit is not going to execute the code within this if statement here. The other logicaloperator that we have is called the NOT operator. And what that’s going to do is it’s goingto take a Boolean, and it’s going to flip it to the other side.So if I take and justas a simple example, if I take and print the value true out, then we’re going to get thevalue true printed out here at the end of our program. If I put the NOT operator, whichis just an exclamation point, and run that, then the true becomes false. Similarly, ifI put this in front of a false, the false becomes true. And I can just prove that falseis really false by taking that away, and false is false. Sothose are the three logical operators that we have. We’ve got the OR operator, whichis the double pipe that you see here on line 10. We’ve got the and operation which is thedouble ampersand, which you see here on line 13. And then we have the knot operation, whichreverses a Boolean result. And that’s done simply using the exclamation point. The otherinteresting thing to know about working with logical operators, is a concept called shortcircuiting. So in order to show you that, I’m actually going to have to jump ahead andadd a custom function here.And we haven’t talked about this. So let me just give youa simple of an explanation as possible. So I’ve got a function down here between line27 and 30, called return true, that’s gonna return a Boolean result. Now in order to makesure that we know that it executed, I’m printing out returning true here, and then I am returningthe true value. So what happens when we call this function is it’s just going to be replacedwith the Boolean true in our application code. Now, up here in line 10, I’ve changed ouror test to include this return true. And this doesn’t make sense in our demo example. ButI’m doing this just to show you how this works. So in this case, we’re ordering three teststogether. So what’s going to happen is go is going to evaluate these guys, it’s goingto generate a result.And it’s going to take that result, and it’s going to order it againstthis guy. So basically, it’s going to evaluate all of them. And only one of those has tobe true in order to generate a validation message. So as you might expect, if we runthis like this, we’re going to get returning true because the guest is not less than one.So we’re going to check this value, this returns true.And so we’re going to evaluate if it’sgreater than 100. None of those are truths or or statement fails. And then we’re goingto drop down and we’re going to execute this code down here. Like we might expect, if wegenerate an invalid value. So if we put a negative five, then well, let’s just run itand we’ll see what happens. So if we run this, we get the validation message.The guestsmust be within one and 100. Well, that’s okay. But what happened to our return true? If youremember, this function is supposed to print returning true out, and it didn’t. So whathappened? Well, what happened is a concept called short circuiting. So as soon as onepart of an or test returns true, then go doesn’t need to execute any more code, it alreadyknows that the old test is going to pass. So it does what’s called short circuiting,which basically means it’s not going to evaluate any other part of the or test, it’s just goingto move on and say, well, the or test passed, and therefore everything works. So in thiscase, since guess is less than one, there’s no reason for go to evaluate these two testshere. So since this test is a function call, it doesn’t even execute that function. Now,if we go the other way, and we go out of range high, then this is going to return false.This is actually going to return true because it’s hard coded.And actually go isn’t evengoing to evaluate this because this is going to return true. However, this value is goingto fail this test here. So if we run this, we see that now we get returning true printedout. So this is a concept called short circuiting. Go is going to lazily evaluate the logicaltests that we put in here. So when we give it negative five, since it doesn’t need toevaluate anything after this first test, it doesn’t. So any function executions are notgoing to be evaluated. The same thing happens for an and test. If one of the parametersreturns false, then we’re going to get a short circuiting here. So if we get into a situationwhere this is false, go will not even evaluate this test here.So for example, with the negativefive, when Google evaluates this, it sees that the guest is not greater than or equalto one. So the ant test has to fail because both sides of an ant test have to return truein order to work and so go is going to exit early It’s not going to execute this code.So for the next thing that I want to talk about, I want to actually drop back into ourbaseline for our test here. And I want to talk a little bit about these two if tests.Now this code obviously works, but it’s a little bit ugly, right? Because we have thislogic here, guess is less than one or guess is greater than 100. And then we have thisexpression here. And this is exactly the opposite. So this is basically saying, Well, if it’snot less than one or greater than 100, then do this other thing. So while this code isperfectly fine, it becomes a little bit of a maintenance nightmare, because really, ourintent is that we want to execute either this code or this code.So the way we can do thata little bit more elegantly and go is by taking out all of this and just putting in the keywordelse. So what’s going to happen in this situation is it’s going to evaluate the logical tests.If these tests return a Boolean true, then we’re going to print this. Otherwise, we’regoing to execute this block here. So in this case, if we run this, we see that we get thevalue too low. And our logical tests down here in line 21. Execute. If we put in thevalue negative five, however, then we get the same behavior that we had before. Butour code is a lot cleaner, and a lot more clear as to our intent. Now related to thatis the situation where we have multiple tests that we want to chain together.Andso let me paste in another permutation of our little game. And in this case, I’ve actuallysplit out the validation logic. So I want to check if it’s less than one, I want toprint out one message, if it’s greater than 100, I want to print out another message.Otherwise, I’ve got a valid value. And to do that, I’m using this else if clause. Sobasically, what this is doing is it’s taking an IF test, and then it’s chaining on anotherif test if this fails.And so what goes is going to do is the first logical test thatpasses is going to be executed, otherwise, it’s going to drop down to the else clause.So with the guests of 30, we would expect our else clause to fire. So if we run, wesee that in fact it does. If we put in a value of negative five, then we would expect thisfirst statement to run and it does.And if we put in a value that’s too high, then wesee that we get the second validation message printed out. And those are the three differentways that we have to create if statements. So we’ve got the simple if statement, that’sjust if and if that evaluates to true, then the statements inside of the curly bracesare going to execute. We’ve got if else. So we’re either going to execute the first setof code or the second set of code. And then we have the if elsif, which we can chain togetherwith else in order to have very complicated branching, so that we can have multiple codepaths execute, depending on how our logical tests execute. Now one thing to keep in mindis through these examples, we’ve never been able to have more than one code path execute.So even if we did something like this, if we did elsif guess is less than one or thenotice both the first test and the second test will pass with a value of negative five,however, goes on and go to execute the first branch that has a succeeding test.So we getthe result, the guests must be greater than one because this test passed. And so thistest wasn’t even evaluated, go immediately went in and executed this branch of code andignored all of the rest of our if statements. Now another thing to keep in mind when you’reworking with equality operators, and this isn’t specific to if checks, but it is somethingthat’s easy to demonstrate with an F check. So if I take a look at this example, here,I’ve got a floating point number of 0.1. And I’m going to check to see if that number isequal to the number squared, and then I’m going to take the square root of it. So ifyou get out of pencil and paper, you’re going to take point one squared, which is goingto be point one, and then you’re going to take the square root of that, which is goingto be back to point one, right? So this should evaluate to true.If we run this, we see thatin fact they are however, if I add in a couple of decimal places here and run this, now gosays the results are different. Well, the fact is that if you square a number and takethe square root of it, it is the same number. So what’s going on here? Well, the thing isgo is working with floating point numbers and floating point numbers are approximationsof decimal values. They’re not exact representations of decimal values. And so we have to be verycareful with them. When we’re doing comparison operations with decimal values, this is generallynot a good idea, the better approach is to generate some kind of an error value and thencheck to see if that error value is less than a certain threshold. So in this case, sincewe’re taking a floating point number and comparing it to a floating point number, what we canactually do is divided two numbers and subtract one.And now what we have is a value that’sclose to zero. So if we take the absolute value of that, so we’ll use the ABS function,which does that from the math package. And then check that to see if it’s less than,for example, point 001. What this is doing is saying divide these two numbers, and ifthey’re within a 10th of a percentage of each other, then we’re going to consider them tobe the same. So if we run this, then you see that the results are the same and we We canadd as many decimal places as we want right now. And the errors that are associated withfloating point numbers aren’t going to get in our way. Now, this isn’t a perfect solution,because you could get two numbers that aren’t truly the same, and get them to pass thistest. So the key to that is tuning this error parameter here, making sure that it’s sufficientlysmall to catch those cases, but sufficiently large, so that the errors introduced withfloating point operations don’t affect your results.Okay, so the next thing that I wantto talk about are switch statements. So let me start that conversation by dropping inan example. And we’ll see a basic switch statement. So a switch statement is a kind of specialpurpose if statement. So where if statement has a logical test and runs a block of codeif that test is true, and then you can add an elsif to run a second test and anotherelsif. And as many else ifs as you want. A lot of times in application development, werun into a set of comparison operations that are very similar to one another. So a lotof times it’s more efficient to use a switch instead of an if statement. So we have a simpleexample here, we’re going to use this switch keyword as you might expect. And in this example,we’re going to start with this value here.And that’s called a tag when we’re workingwith switch statements. So this is what we’re going to compare everything against, thenwe’re going to have a series of cases. And you can see here we got case one, and we gotcase two. So what’s going to happen is the value here is going to becompared to the tag.And if it’s true, then the statements after the case are going toexecute. If not, then they’re not going to execute. And just like with if statements,the first case that passes is going to be the one that executes, we also have this defaultcase down here. And that’s going to execute if none of our other test cases passed. Soif we go ahead and run this, we see that we get to print it out. If we add the value onehere, we get the value one printed out. And if we have three, then we get the defaultcase printed out. So it’s a very simple way to compare one variable to multiple possiblevalues for that variable. Now in a lot of languages, if you want to compare againsta range, then you’d have to do something like this, you’d have case two, you’d have casethree. And then we use what’s called falling through in order to compare multiple casestogether, well, we don’t actually have falling through as a default behavior and go, butwhat we do have to make up for that is the ability to have multiple tests in a singlecase.So if I extend this example out here, and I say this is going to test one, five,and 10. And this is going to test two, four, and six, then I’m going to say this is goingto print out one, five, or 10. And this will print two, four, or six, and then I put inthe value five, and let’s just change this message to this is going to say another number.Okay, so if I run this, then I get the first case is going to pass because I matched thissecond test. So this is going to execute if I have the value one, five, or 10. So I canalso get into that same case by passing in the value of one, if I pass in the value offour, then like you might expect, I’m gonna have the second case, evaluate. And naturally,if I pass in an unknown number, then I’m going to have the default case execute, just likeI had before with a single test. Now one thing we have to be aware of is the test cases dohave to be unique. So if I try and run this, where I’m going to have five in the firstcase, and in the second case, that’s actually a syntax error, because you can’t have overlappingcases when you’re using this syntax.Now, just like with if statements, we don’t haveto have a simple tag here, in our switch, we can use an initializer, just like you’reseeing here. Now, in this case, the initializer doesn’t have to generate a Boolean result,because we’re not doing a Boolean test in our switch statement up here, the Booleantest is comparing the second parameter in the switch statement to our cases. So in thiscase, we’re just going to initialize that value. So I’m doing some simple math here,I have set equal to two plus three. So obviously, that’s going to be five, then I’ve got thesemi colon and the tag that we’re going to be testing against. So as you might expect,when I run this, the first case executes because two plus three is five, five is matched bythe first case.And so we get this statement printed out. Now another syntax that we haveavailable to us in switch statements is a tankless syntax. So both of the styles thatwe’ve been talking about, we’ve always had a value that we’re comparing to our test cases,where there’s actually another syntax, this tag list syntax. And this is arguably morepowerful than the tag syntax, although it is a little bit more verbose. So in this case,on line eight, I’m establishing a variable which is going to come from some other logicin my application. And then I’ve got the switch statement that standing all alone and immediatelyopening a curly brace. So notice, I don’t have a tag here. However, my case statementsnow I’ve got full comparison operations. And I can use the comparison operators, I canuse the logical operators. So in this case, the cases are standing in for the logicaltests that we have in our if statements, they’re doing exactly the same job.So in our firstcase, I’m checking if i is less than or equal to 10. And if it is, I’m going to print thatout. And then in our second case, I’m going to check if i is less than or equal to 20.And then of course, we’ve got the default case. If The value falls through. So if Irun this, I see that I do get the code executing, which is an interesting thing. And it executesthe first case. Now, why is this interesting? Well, if you notice the first case, in thesecond case overlap, because 10 is less than or equal to 10. It’s also less than or equalto 20. So unlike the tag syntax, we’ve got multiple test cases. And I said they cannotoverlap. When we’re using this tag list syntax, they are allowed to overlap. And if they do,then the first case that evaluates to true is going to execute. Now another thing thatI should have pointed out earlier is notice that we don’t have curly braces around this,any statements that after this case, and before the next case is going to be part of the blockthat’s going to execute, so I can have as many statements as I want here.The delimiters,in this case, are the actual case keywords, the default keyword, or the closing brace,so any of those delimit the end of a block in a case statement. Now again, if you’recoming from another language, then this syntax might be looking a little weird, because youmight be looking for this word coming in here. And we’ll have to add this word here. Andwe’ll have to have this word here. So you might be wondering where the heck aremy break keywords, one go, the break keyword is actually implied, because so many use casesfor switches have breaks in there. And forgetting a break is the cause of innumerable errorswhen working with switch statements, the design decision was made to have an implicit breakbetween our cases, instead of an implicit fall through which most other c based languageshave.So what happens if you do in fact want your case to fall through. So in this example,let’s just say that we do want to print out that we’re less than or equal to 10, and thatwe’re less than or equal to 20. And we know that if we pass this first case, we’re goingto pass the second case to, in that case, we can actually use the keyword fall through.So if I run this, you see that both messages print out. So I’m going to get less than orequal to 10 and less than or equal to 20. Now one thing to keep in mind here is fallthrough is logic less. So when we say fall through to the next case, it will do that.So if I, for example, change this to be greater than or equal to, then we know that I failsthe second case, but if I run, it still executes, because fall through means that you are takingthe responsibility with the control flow. And you intentionally want the statementsin the next case to execute. Now and go you don’t use follow through very often, becausewe have that tag syntax that can take multiple tests per case.And so a lot of the use casesfor falling through are taking care of that. However, if you do have a use case where youneed follow through, then it is available to you. The next thing that I want to talkabout was switch statements are a special use of a switch statement called a type switch.So I’m going to drop in this example here. And this should be pretty familiar exceptfor what we’re switching on. So notice that we are switching on a tag. But the tag variableis typed to type interface, which can take any type of data that we have in a go application.So the interface type can be assigned to an integer like we’re seeing here, we can assignit to a string to a Boolean, to a function to a struct to a collection, anything we wantto assign to an interface is going to be permissible.So then in go, we can use this syntax here.So we can put in the dot operator. And after that, put in params with the word type inthe middle. And what that’s going to do is tell go to pull the actual underlying typeof that interface and use that for whatever we’re doing next. Now, you don’t just usethat for type switching. But this is a common use case for it. So in this case, I’m goingto assign the variable i the value one, which as we know is going to type I to be an integer.And then I can actually use go types as the cases, because this is going to return a type,then I can use those type keywords here as my cases.So if I run this, knowing that oneis an integer, I should not be surprised when I see the first case passes, and the othertwo are ignored. If I had a decimal point zero here, then that’s going to turn thisinto a floating point 64. And we see that go recognizes that. Similarly, if I put onein a string here, then we’re going to see that go understand that.And I can even make,for example, an array. And we don’t need to initialize any values here. But if we seethat, then go recognizes that as another type. And if I want to have a case to catch that,then I can actually have a case for a raise of three integers. And then I can print thatout. Now if I run, we see that it recognize that and this is different than two. So ifI use a two element array, please be aware that those are different types. Arrays arenot equivalent to every other array, you have to have the same data type and the same arraysize in order for them to be evaluated as the same type.Okay, the last thing that Iwant to talk about I can illustrate with this example here. Now in this example we’re extendingon the previous one was type switches. And notice that I’ve got these two print statementshere on line 11 and line 12. So if I run this, I see that I is an integer and this will printto it. In some situations, you might need to leave a case early. So maybe inside ofthe case, you’re executing some kind of a logical test, and you find out that thereis some logic in the case that you don’t want to execute in certain situations. Well, ifyou want to do that, you can actually exit out of the switch statement early by usingthe break keyword.So if I add that and run, then I have a way to break out of the switchearly. And I’m not going to execute any code below that break statement. So you can wrapthis in a logical test to determine if you’ve got a validation error. For example, on someincoming data, you might not want to save that data to the database. And then you canuse this break keyword in order to short circuit that save operation. Okay, so that prettymuch wraps up what I have to talk about with if and switch statements. Let’s go into asummary and review what we’ve talked about. In this video, we started our discussion aboutthe different control flow tools that we have available to us in our NGO applications. And we startedout by talking about the very basic if statements and how we can use a boolean variable to determineif a block of statements will execute or not. We then talked about the initializer syntax,and how that allows us to execute a statement, that’s going to set up variables that we canuse to run our test against as well as use within the statements of our if tests.Wethen talked about the comparison operators, and we talked about how there are six of them,we’ve got less than, greater than, less than or equal to and greater than or equal to,to work with primarily the numeric types, as well as the double equals operator andthe non equals operator that are available to be used more generally, we talked aboutthe logical operators, the AND operator, the OR operator and the non operator that allowsto chain together Boolean operations, as well as reverse the result of a Boolean operation.In the case of that knot operator, we talked about short circuiting and how when you’rechaining together tests with an OR operation, for example, if any one of those logical testsevaluates to true, then the remaining tests are not executed.So any side effects or anyfunctional operations that might occur with those are not going to be executed. Similarly,with an an test, the first part of an ad test to return a false result is going to haltthe execution of that and test. So any side effects you might be relying on afterwardare not going to occur. We then talked about the two different variants of if tests, wetalked about the FL statement, and how we can use that to execute one of two branchesof code. So if the if test succeeds, then we’re going to execute the first block ofstatements. Otherwise, we’re going to execute the second block of statements. Related tothat is the if else if statement. And in this case, instead of determining between one oftwo paths, and forcing your code to execute one of those, you can add additional logicaltests. So at most one block is going to execute.But if all of your F tests fail, then youmight not get any blocks executing. And finally, I took a minute to talk about equality operations,especially when working with floating point numbers. And how equality and floats don’treally get along that well. So if you do need to do some kind of inequality operation withfloating point numbers, then you’re going to want to turn that into some kind of a comparisonoperation against an error function. So for example, we were checking to see if two floatswere equal, instead of checking to see if they’re actually equal, and we divided themsubtracted one from that result, and check that against an error parameter. So we decided,if they were within a 10th of a percent, they were going to be considered the same, youcan use a similar type of error function with your operations.But in general, you shouldnot test to see if two floating point numbers are equivalent to one another. We then movedon to talk about switch statements, and the various ways that we can use those in ourapplications. We started by talking about how to switch on a tag or tag is just anothername for a variable. But that variable has a special significance in a switch statement,because all of your test cases are going to be compared back to that tag. We talked abouthow with go we can have multiple tests with our case statements. And by doing that, wecan actually eliminate a lot of situations in other languages where we need to fall throughand chain multiple cases together. Well in go, we can just add those multiple tests inthe same case, and eliminate the need to do that following through.We also do have initializersavailable with switch statements. But instead of the initializer, generally generating aBoolean as we do with an if statement, the initializer is going to generate the tag that’sgoing to be used for the comparisons. In our cases, we talked about switches with no tagsand how it adds a lot of flexibility to the switch statement. But it is a little bit moreverbose syntax. So instead of the cases being compared for equivalency with the tag, we’regoing to actually put in the comparison operation ourselves. So we can use more than just equivalencytesting we can check less than or equal to, or any other comparison function, includingchaining comparisons together by using logical operators. We talked about how we have thefall through keyword available in switches, and how that replaces the break keyword inmany languages. So where many languages have implicit fall through an explicit breakingin go we flip it around so we have implicit breaks.But if you do need one case to fallthrough to the next Then you can use this fall through keyword. Now one thing to keepin mind when you’re doing that is when you’re falling through, any additional case logicis not executed, the fall through will override any case logic that you have. And so the nextstatement will execute regardless of if that case would normally pass or not. We also talkedabout type switches, and how we can use that special syntax by adding a dot perenne typeperenne on an empty interface in order to get the underlying type of that empty interface.So for example, if we’ve got an empty interface that’s holding an integer, then we can usethat syntax in order to get that underlying integer value. Then in our switches, we canswitch against those types.And then we can make a decision based on the data that wegot in. And finally, we talked about breaking out early, when we’ve passed into a case inour switch statement. There are times when, in the middle of the case, we need to exitout early, because we’ve done some additional analysis. And we’ve decided that we shouldnot proceed executing this case. So for example, we’ve got a switch statement.And inside ofthat case, we’re doing some validation on the data before we save it to the database,we might decide that data is invalid, and we should not proceed to save it to the database.So in that case, you can use the break keyword break out of the case and continue executionafter the switch statement, I want to continue our discussion of the control flow structuresthat we have available in the go language by talking about looping. Now in the lastvideo, we talked about the two ways that we have to introduce branching logic into ourapplication if statements and switch statements.Well, when we talk about looping and go, thingsare actually going to be a little bit simpler, because we only have one type of statementthat we’re going to have to learn. And that statement is the for statement. Now we’rebasically going to break this conversation down into three different parts, we’re goingto talk about simple loops, we’re going to talk about how we can exit a loop early. Andthen we’re going to talk about how we can loop through collections. Okay, so let’s goahead and get started by learning how to do some simple loops in go. So in order to start our discussion aboutlooping and go, I want to start with this perhaps the most basic for loop that we cancreate.So we’re going to start with the for keyword as you might expect. And then we’regoing to follow the for keyword with three statements, the first statement is going tobe an initializer. Now this is the same as an initializer. And if statements and switchstatements. So we can add any kind of statement that we want here. And normally, we’re goingto use that in order to set up a counter, when we’re using a for loop like this, thenext statement that we have here is going to be some kind of a statement that generatesa Boolean result. And that’s going to be used by the for loop to determine if it’s donelooping or not. And then the last statement is going to be the incrementer. And normally,we’re going to use that in a situation like this to increment a counter variable. So ifwe run this, we see that we get the numbers zero through four printed out, we could alsoincrement i by two. And there, you see that we only get three iterations of the loop,because I has the value zero, then it has the value two, and then it has the value four,when it comes to the next time it has the value of six, well, six is not less than five.Therefore the comparison operation results to false and we exit out of the loop.So thisis certainly possible to do and you will occasionally see this. But the most standard way that yousee these loops created is like this using an increment statement. Now if you’re comingfrom another language, you might be expecting to be able to do something like this. So maybewe want to variables, increment in our for loop. And so we’re going to initialize j there.And then we’re going to increment j with each loop. So if we go ahead and try and run this,we see that that’s actually not allowed, because we have no comma operator in the go language.So you can’t separate two statements like this using the comma. So this is an error,and this is an error. So if we want to do that, though, we can use gos ability to initializemultiple values at the same time by adding a comma here getting rid of this part here,adding the comma there.And then we can’t treat these as individual statements, becauseyou can only have one statement here. And in go the increment operation is a statement,it’s not an expression. So we need to figure out a way to do both of these at one time.So we will simply come in and said I n j equal to i plus one and j plus one. And go aheadand run that. And now we have I printing out if we have j here we see that j printout aswell, we can actually increment j by two here. And we see that i and j are incrementing independently.And we have no problems here. Now just to come back and revisit that increment commentthat I made earlier, you might be tempted to do something like this, if you just wantto increment them by one.If we run that, we’re actually going to get an error becauseagain, in go unlike a lot of languages, the increment operation is not an expression.So we can’t use that as part of a statement. It is a statement on its own. So when you’rejust incrementing one variable, you can certainly do this because i plus plus is a statement,but we can’t use that in combination with anything else. We can’t use it as an expression.Something else that’s interesting. Let me go back to our initial example here. So wecan play around with this a little bit. So at first blush, if you just come into programming,this AI variable might seem like it’s something special because it’s used up in the for loop.And the fact is, it’s a variable just like anything else. So we can do whatever we wantwith it. As a matter of fact, just to show you that, let me drop in this cool littlebit of code.As you can see, what we’re going to do here is we’re going to take the modulusof i n two, and we’re going to see if that zero, so basically, we’re checking to seeif it has an even number or an odd number. If I is an odd number, then we’re going todivide it by two. If I is an even number, then we’re going to multiply it by two andadd one to it, it’s just a couple things to play around with the incrementer. So let’srun this and see if this actually goes to completion. And in fact, it does. And yousee that the variables going all over the place. So we start with zero zeros on so dividethat by two, which stays zero, the next iteration is going to be one because we’re incrementingby one, so it’s actually going to be multiplied by two and one added to it.So we print theone here. But then by the time we’re done here, two times one plus one is three, andso is three, that gets incremented to four, so we’re printing for four out here, fouris even to divide that by two, two gets incremented again, so we print out the value three, threeis odd. So three times two is six plus one is seven, seven is greater than five. Andso we leave the comparison operation, so we can do whatever we want with the counter.Now, just because you can play with the counter doesn’t mean it’s a good idea. As a matterof fact, normally, it’s very bad practice to manipulate the counter within the for loop.So maybe the best reason to show you that you can do this is to make sure that you avoiddoing this because there can be times when you’re inadvertently changing the countervariable within a loop. And your loops might start to act really strange, like we’re seeingin this example here. Okay, so let’s go ahead and restore our original example, make surethat that’s running again, and it is we’re printing out the values zero through fouragain.Now the next thing that I want to show you is that we don’t actually need all threestatements here. So one thing that we could do, let’s just say that I is initialized somewhereelse in our application, so we don’t need it to be set up here. And we can run withthis first statement being empty. Now you can’t leave this for a semi colon out, becauseif you leave that out, then everything’s in the wrong place. And it thinks that this isgoing to be the initializer. And this is going to be the comparison operator. So if we tryand run this way, we’re going to get an error. But if we leave the semicolon in, then gorecognizes that we simply don’t have an initializer in this for loop. And it executes everythingthe way that we expect it to. And of course I’ve variable ri is taken in just like wewould expect.Now the difference between this format and the previous one is in this i isscoped to the main function. But when we have this syntax here, I is scoped to the for loop.So if I tried to print the value of i out here, we’re not going to get a valid valuebecause I is not defined. But in this other form, when we’re putting it out here, thenI is scoped to the main function. And we are actually going to get the final value of Iprinted out which is the value five, because five is the first value that fails this test.So this is actually coming from this statement right here. Okay, the next thing that we cando, let me go ahead and wipe this out, we also don’t need the incrementer value, sowe can eliminate that.Now if I run this right, now, we’re actually going to get an error,because what this is going to do is it’s going to generate an infinite loop. And in the goplayground, they don’t let us do infinite loops. And so after it runs for a little bitof time, it’s going to shut the process down on us. If we were actually running this ina local environment, all you’d see is the value zero printed out over and over and overand over again, until eventually you got bored and shut the application down. Now we canof course, since I is a variable just like any other, we can put the incrementer in here,and everything works just fine. So once again, we have to remember to put the semicolon here,if we remove the semi colon, then go doesn’t know what the heck we’re asking it to do,because this is invalid syntax. So if you have the first semicolon, you need the secondsemi colon. Now this case does happen actually quite a bit where we need a for loop and justa comparison operation.And this is how go does do while loops. So in a lot of languages,you have two more keywords, you’ve got the do keyword and the wild keyword. And normallythose work with simply a logical test. And then you have some other increment operations.So you either have an increment or inside of the loop, or you’re pulling the next valueoff the stack. And comparing that on each iteration, or something like that, we’ll gohas the same problems to solve, but didn’t make sense for the designers of the languageto introduce a new keyword just for what is basically a special case of a for loop. Sowhat they allow us to do is we of course can use this double semi colon syntax here. Butyou can also leave them both off. So if I run this way, we see that this works. Andthis is going to work exactly the same way as if we have both of these semicolons here.So this is a little bit of syntactic sugar. It’s exactly the same construct. It’s justyou don’t need to have the additional semi-colons and it reads a little bit cleaner.So in thiscase, our for loop is just doing a comparison operation. Go is going to assume that we’retaking care of where those variables for the comparison are coming from somewhere else.Now the third form of a for loop that we have available when we’re working with counterslike this is the infinite for loop. Because we also have a situation with do while loopsin other languages, where we need the application to run through the loop and undetermined numberof times.And by undetermined means, we don’t actually know when to stop by an obvious logicaltest, we need some complex logic within the loop in order to determine when to leave.So in go, the way that we do that is we simply leave off the logical test, and we run likethis. So if I run this, again, as you might expect, the playground is going to crash outon us because there’s no way for the program to exit. And so it’s just going to run forever.So we need some way to tell our infinite loop when it’s done processing and when to leave.And the way we’re going to do that is using the break keyword. And then Normally, theway that you do this is you’ll put some kind of logical tests inside of the loop. So wecan say, if I equals five, then we’re going to use that break keyword.And we saw thebreak keyword, the first time when we were talking about switch statements, or the breakkeyword is actually more commonly used inside of for loops, especially this kind of infinitefor loop here. So what we’re doing here is if i is equal to five, so we’re going to printout the values, zero through four, then when I was fine, we’re gonna break out.So if wego ahead and run this, we get exactly the same values that we had before. Now when wedo this, we actually leave the entire for loop. So execution of the loop stops, andwe’re done processing. Now another thing that we can do is use what’s called a continuestatement. So let me drop in an example that shows you that. So in this case, we’re loopingfrom zero to nine, because we’re going to keep incrementing as long as i is less than10. And then we’re checking to see if the value is even if it is even, then we’re goingto use this continuous statement here. And what this does is it basically says, exitthis iteration of the loop and start back over. So what’s going to happen when we have00 modulates to is zero, so we’re going to continue, which means we’re not going to hitthis print statement, when we have one, one minus two is one, so we’re not going to hitthis continue, and we’re going to print out one, and then two is going to hit the continueand three is not.So what we should see is we’ll only print the odd numbers out. If werun this, we see that that is in fact what happens. So continuous statements aren’t usedvery often. But they can be very, very useful. If you’re looping through a large set of numbers,and you need to determine within the loop whether you want to process a record or not.Now, to show you the next thing, I’m actually going to do this, this is actually going toprint out a nested loop.So what we’re doing here is a pretty simple example, we’re startingwith the variable, I initializing it to one, and we’re going to run as long as i is lessthan or equal to three, and then we’re doing the same thing with J on the inside. So basicallyis going to be one, then it’s going to loop through days from one to three, then is goingto be two, it’s going to loop through j 4123. Again, and then inside this inner loop, we’rejust multiplying the two numbers together.So if we run this, we see that we get allof the permutations of i times j, where i and j go from the values 123. So we get allof these values printed out, and everything works the way that we expect. Now what happensif we want to leave the loop, as soon as we get the first value that’s greater than three.So what we want to do is something like this, so we’re going to multiply it times j, we’regoing to repeat our logic here. And we’re going to see if that’s greater than or equalto three, if it is, then we’re going to break out of the loop. Now if I run this, we don’texactly get the expected result. And the reason for that is as soon as i times j is greaterthan three, it breaks out of the loop, but the loop that is going to break out of isthe closest loop that it can find.So it’s actually breaking out of this loop here. Andthis loop just restarts because there’s nothing to tell it to stop. So you might ask the question,Well, how do we break out in the outer loop? Do we have to have more logic here and checkto see if i times j is greater than three again, and then break out? Well, the answeris, of course, now, we do have a concept called a label that we can add. So a label is puttogether something like this, we’re going to start with a word and follow it with acolon. And we’re going to left justify that in our code blocks. So once I have a labeldefined, I can actually add the label after the break keyword.And it basically describeswhere we want to break out to. So since this labels just before this for loop, we’re goingto break out of the outer for loop. So if I run now, I get to the value three, threeis greater than or equal to three. And so I break out of both the inner and the outerloop. The last thing that I want to talk about in this video is how we can work with collectionswith for loops. So we’ve seen this before we have a slice of integers. In this case,we’re containing the values one, two, and three. And we’ve seen how we can work withthis as a slice so we can print this out. We run this we get no big surprise, we getthe slice printed out with the values 123. But what happens if I wanted to work witheach individual value? Well, we’ve seen how we can do this, we can pull out one valuefrom the slice, and we get the value two. But how do we work with an arbitrarily sizedslice. So I don’t know how big this slice is going to be at runtime.I want to be ableto loop through all the items within the slice. So the way that I’m going to loop througha collection is using a special format The for loop called a four range loop. So I’mgoing to start that with the four keyword as you might expect. And then what I’m goingto get is both the key and the value for the current item in the collection. So I’m goingto have two variables that I can set there.And then I’m going to set that equal to thisspecial range keyword and then provide the collection that I’m going to range over. Sowhat this is going to do is it’s going to look at the collection here. And it’s goingto take each value one at a time, give us the key and the value, and then we’re goingto be able to work with those values independently. So inside of this, let’s go ahead and justprint out the value of the key and the value and run that. And you see that we get theindexes for the items in the slice, and we get their values.So the indexes are comingfirst, those are the keys. And then the values are the actual values in the slice. And thisis the only syntax, you have to remember when using the range keyword, you’re always goingto get this key comma value result coming out. So this syntax is going to work for slicesand for arrays. So if we make this an array by just adding a size, here, we see that weget the exact same output, we can loop over maps. So if I pull back the state populationsmap that we use for a couple of videos now, and loop over that, once again, pulling upthe key and the value and ranging over the map this time, then if I print the key andthe value, I’m going to be able to split that out and then get the state in their populationprinted out separately.And I can even use a string as a source for a four range loop.Because what we’re going to be able to do here is pull each letter out of this stringas a character and look at that. And we see that we do get each position. And now we getthis numeric value, which if you’ve been paying attention over the last few videos, you’regoing to remember that this is actually the Unicode representation for that digit. Sowe can cast it back to a string by just using a simple conversion operation. And we seethat we get each letter printed back out as we would expect. The other type of data thatwe can arrange over in go is what’s called a channel.Now channels are used for concurrentprogramming and go and that’s a topic for a future video. So I’m going to leave thattopic right now, I promise when we talk about parallelism and concurrency and go, I’ll revisitthe for loop and show you how you can use for loops with channels, because there aresome special behaviors that you have to be aware of when you’re ranging over channels.Now, if I come back to this example, and print this out, you see that we have access to boththe key and the value every time.Now, this is not always true, you don’t always needaccess to the value. And this can lead to some problems. Because if I only want to printthe keys out and run this, this is actually an error, because in go, you have to use everyvariable that’s declared. And so we got this situation where we’ve got this variable v,but we’re not using it. And so that’s going to cause us a problem with our application.Now and go what you can do, if you only want to get the keys out, you can actually skippedthe comma value.And when you run that, it’s going to ignore the value. But what happensif you get into a situation where you only want to print the value out. So if I restorethis, and I want to want to print the value, of course, I get the same error. But I can’tjust say this, because go who’s going to assign the keys to that. So what do I do? Well, inthis situation, when you only want the values, then you can use that underscore operatorthat write only variable that we’ve seen a couple of times. And basically, that’s goingto give a hint to the compiler that we don’t actually care about the key. But we need thisin this first position in order to get the value. So when we run this, we do see thatwe get those populations printed out. Okay, so that covers what I want to talk about withfour statements and go, let’s go into summary and review what we’ve talked about.In thisvideo, we talked about the second major control flow construct that we have in the go language,the looping construct, and we talked about how we’re going to use the for statement forall of the loops that we need to do and go. So we don’t have to remember I do keywordand while keyword and a for keyword, when we use the for keyword that’s going to allowus to loop over every collection that we have. We started by talking about simple loops andhow there are three basic forms for the simple loop, we’ve got this first syntax, which isthe most basic, that’s the initializer test incrementer syntax, and we’re going to usethat initializer to set us up in our loop. Normally, by initializinga counter variable, then we’re going to follow that with our test, our test is normally goingto look at the incrementer to see if it’s at a certain value that’s out of range forour for loop.And then we’ve got an incrementer and that incrementer. His job is to move theincrementer along at every iteration of the loop in order to move to the next case thatwe want to loop through. Now we also learned in this first syntax, we actually can leavethe first and last statements on that out. But if we’re going to use any of this syntax,we have to leave the semi colons in place. So leaving a semi colon out confuses the compiler,it starts to assign things to the wrong places. And so you’re going to get an error in yourapplication. So if you need an initializer or an incrementer, then you’re going to haveto use this full syntax. Now the second syntax eliminates the need for the initializing theincrementer. And it assumes that the test conditions are being managed somewhere else.So in this construct, you only have the for test.And as soon as that test is false, you’regoing to exit the loop. The last construct that we have is the for loop on its own andthat will run indefinitely. Until somewhere within your four loop, the break statementis called. That leads us to how we can exit early from a for loop. And we have three conceptsthat we talked about with that, we’ve got the break keyword that will break out of theimmediate loop that’s executing and continue the application execution after that loop.The continue statement is similar to the break statement, except for eight doesn’t breakout of the loop, it just breaks out of the current iteration goes back to the incrementer,and continues execution of the for loop at the next increment.Now we can also use labelsin our application and combine those with break statements in order to break out ofan inner loop. And that’s typically how they’re used in go. So for example, if you have anested loop where you’re iterating over two collections, and you need to break out ofthe outer loop, then you need to set up a label and then follow the break keyword withthe name of that label so that Google knows where to break out to. And finally, we talkedabout how to loop over collections, and how the collections that we have available, there’squite a few we’ve got arrays, slices, maps, strings and panels that we can loop over.But they all have this similar syntax, we’re going to use that for keyword, we’re goingto get a key and a value. And then we’re going to set that equal to the range keyword followedby the collection that we’re looping over. So the keys when working with arrays, slicesand strings are going to be the index within that collection. So you’re going to have thatzero based index.With maps, we’re going to get the key from that map. And the valuesare what you expect them to be. They’re the value for that current index. Now when we’retalking about channels, it’s going to follow very similar syntax, but channels have a littlebit of a special interpretation for these. And we’ll talk about those in a future module,I’d like to finish our discussion of control flow constructs that we haven’t go by talkingabout defer panic and recovery.We’ll start that discussion by talking about deferredfunctions, and how we can actually invoke a function, but delay its execution to somefuture point in time. Then we’ll talk about how an application can panic. So in this conversation,we’ll talk about how go application can enter a state where it can no longer continue torun and how the go runtime can trigger that as well as how we can trigger that on ourown. And then related to panicking, we’ll talk about recovery. Now when your applicationstarts to panic, ideally, you’d have some way to save the program so that it doesn’tbail out completely. So we’ll talk about if your application can be saved, how you canuse the recover function in order to signal that to the rest of your application. Okay,so let’s go ahead and get started.In a normal go, application control flows from the topto the bottom of any function that we call. Now, of course, we can alter that a littlebit by introducing branching logic so that we can skip some statements. And we can uselooping that we talked about in the last video to repeat certain blocks of statements multipletimes.But generally, a function is going to start at the first line and execute throughuntil it gets to the last one. So if we run this program right here, we see that it’sno big surprise that we print start, then we print middle, and then we print end. Andwhat we can do if we want to defer the execution one of these statements is proceeded withthe defer keyword. So if I put that in front of this print line here, then run that, younotice that middle is actually printed after end. So the way the defer keyword works ingo, is that it actually executes any functions that are passed into it after the functionfinishes its final statement, but before it actually returns.So the way this main functionis executing is its calling line eight and it’s printing out start, then it recognizesthat it has a deferred function to call and then it prints out end. And then the mainfunction exits now when go recognizes that that function exits, it looks to see if thereare any deferred functions to call. And since we have one, and then goes ahead and callsthat, so deferring doesn’t move it to the end of the main function, and actually movesit after the main function. But before the main function returned. Now, if we put thedeferred keyword in front of all of these statements, then we’ll actually see an interestingbehavior. Because the deferred functions are actually executed in what’s called lifepoorder or last in first out. So the last function that gets deferred is actually going to bethe first one that gets called.And this makes sense, because often we’re going to use thedeferred keyword to close out resources. And it makes sense that we close resources outin the opposite order that we open them, because one resource might actually be dependent onanother one. So if we run this like this, we actually see that we’ve reversed the orderof printing this. So we’re now printing and middle and start. And just to remind you,these aren’t executing in the context of the main function they’re executing after themain function is done, but before it returns any results to the calling function. Now,these are good theoretical examples. But in this situation, I felt it makes sense to geta little bit more practical example for you to look at. So for this, we’re actually goingto need to go into Visual Studio code, because we’re going to need to run a program that’sgoing to make some resource requests through the HTTP package. And you can’t do that ina playground. So if we look at this program, here, we’re importing a couple of packages.Then we’re using the get function from the HTTP package in order to request the robotsdot txt file from google.com.Now this example you can actually find in gos documentation.I basically stole this as an example for how you can use the deferred function. Now, asyou can see, with this request, we’re going to get a response and an optional error. Andwe’re going to check to see if that error is nil. And if it’s not, then we’re goingto log that out and exit our application. If it is not nailed, and we got a good response.So then we’re going to use the read all function from the IO util package, what that’ll dois that’ll take in a stream, and that’ll parse that out to a string of bytes for you to workwith.So if we look at the robots variable, here, we see that that is a string of bytes.And then we close the body of the response to let the web request know that we’re doneworking with it, so it can free up those resources. Of course, the read operation can fail, sowe’re checking for that error. And then we’re finally going to print out the value of therobots variable here. So if we run this application, by invoking it with the go run command, wesee in fact that we do get the robots printed out, and everything worked out just fine.So we got this entire response printed out to the console here.Now, one thing that we’redoing here, and that the defer keyword can help with is handling this body close. Now,in this application, we only have one statement that’s really being worked with between therequest being made, and the body being closed. However, in many applications, you might havequite a bit of logic that’s involved, that needs that body to be open and continue towork with it, maybe you’re reading this stream one character at a time, and you’re doingsome pattern matching or something like that.So you can actually end up with quite a fewstatements in here. So what can happen here is that you might make this request and openup this resource up here. And then it might be dozens of lines later that you actuallyget around to closing in. Well, that introduces the possibility that you forget to close it.Now, it’s going to be hard to find that it’s going to be hard to remember to close theresource. And so you’re introducing the possibility of bugs coming into your application.So whatwe can do is add the defer keyword here. And then we can go ahead and move this up a line.So if we run this, then it looks like we’re closing the resource, and then we’re tryingto read it. But if we run the application, we see that it works just fine. Everythingcomes out the same way it did before.Now if we leave the defer keyword off, then we do get an error because we closedthe response body before we were done reading it. So what this allows you to do, and thisis the most common use case that I’ve seen for using defer is it allows you to associatethe opening of a resource and the closing of the resource right next to each other.So you see this pattern a lot where we’re going to open resource, we’re going to checkfor an error. And then we’re going to close the resource. And you want to check for theerror first. Because if there’s error generated here, then you actually never got this resource.And so trying to close, it will cause your application to fail.But as long as you knowthat you have the resource there, then it makes sense to do a deferred call to closeit. Now, one thing I would warn you about is this is a pretty common pattern. And you’regoing to see this all the time. But if you’re making a lot of requests and opening a lotof resources within a loop, then using the defer keyword to close, it might not be yourbest choice. Because remember, the deferred statements don’t execute until the functionitself executes. So if you’ve got a loop that’s going to loop over a million resources, you’regonna have a million resources open before all of those get closed at the same time whenthe function finally executes. So if you’re working with resources in the loop, then youmight not actually want to use the defer keyword, you might want to explicitly close those resourceswhen you’re done with them.Or another option would be to delegate the processing of thoseresources out to another function and have that function, close the resource. That way,you’re not keeping a bunch of resources open at one time and wasting memory. Now the nextthing that I want to show you we can do back in the playground. So I want to do that, becauseI think that’s the most accessible environment that we have is this program here. So whenI run this program here, what do you think is going to print out when I run this, nowthere’s two lines of thought that you might have, the first line of thought is, well,I’m defining a is the string start. And so I’m going to print start out. But you mightalso realize the defer statement is going to cause this statement to print after themain function is done. And before main is done, we’ve already changed the value to end.So you could make an argument that this is going to bring start or end with the factis that we’re going to get the values start printed out.And the reason for that is whenyou defer a function like this, it actually takes the argument at the time, the deferis called not at the time the called function is executed. So even though the value of ais changed, before we leave the main function, we are going to actually eagerly evaluatethis variable. And so the value start is going to be put in here, we’re not going to payattention to this value as it changes. Now the next thing that I want to talk to youabout in this video, is what’s called panicking. Now in go, we don’t have exceptions, likea lot of applications have, because a lot of cases that are considered exceptional anda lot of languages are considered normal in a go application.For example, if you tryand open a file, and that file doesn’t exist, that’s actually a pretty normal response.It is reasonable to assume that you might try and open a file that doesn’t exist. Andso we return error values. We don’t throw exceptions because that’s not considered exceptionaland go. However, there are some things that get a go application into a situation whereit cannot continue and that is considered exceptional. But instead of using the wordexception, which you has a lot of connotations because of its use and other languages, we’regoing to use another word and that word is going to be panic.And that’s because ourapplication can’t continue to function. And so it’s really starting to panic because itcan’t figure out what to do. So if we take this example, here, I’m declaring two variablesa and b, and setting a equals one and B equal to zero. Now, obviously, the answer of onedivided by zero is invalid, we can’t do that in a go application. So if I run this, we’reactually going to see that the runtime itself will generate a panic for us. And the runtimeerrors printed out integer divide by zero.And then we get a stack trace letting us knowwhere that error occurred. Now, if you’re going along and writing your own program,and you get to a situation where your program cannot continue to execute, because of a certainstate that gets thrown, then it makes sense for you to panic as well. So to do that, you’regoing to use the built in panic function like we see here. So we’re printing out start,then we’re using the built in panic function passing in a string, and then we’re goingto print out. And what’s going to happen when we run this is very similar behavior to whenwe had that divide by zero error a few seconds ago, but the error message that’s printedout is actually going to be the string that we passed into the panic function.And thennotice we get the same stack trace out, we do get start printing out. But of course,we don’t get the string end printed out. Now more practical example. Now this willnot run in the playground. But that’s okay, because it probably wouldn’t fail on the playgroundanyway, is this one here. So this is a very simple web application where you’re goingto use the handle function. So we’re registering a function listener, that’s going to listenon every URL in our application. And then this is a callback that gets called everytime a URL comes in that matches this route. And all this is going to do is print out thestring hello, go. As a matter of fact, why don’t I go ahead and do this over in VisualStudio code, that way, you can see what this program is going to do. So we’ll go aheadand save this and we’ll get it up and running. Now there’s no errors and went ahead and started,okay.So if I come in, and hit that URL, which is localhost 8080, that you see that we getthe string hello, go printed out. There you go an entire web development course in onevideo. So we’ve got a very basic web handler that’s printing out the string, hello, go.And that’s coming from this line right here, where we’re writing to this response writer,this response writer is basically giving us access to the response to this web request.And we’re printing out the string hello, go. Now, what’s interesting here is this errorhandler right here. So the listening serve function returns an optional error object.So when might that happen? Well, one situation that can happen all the time, when you’refiring up a web server is the port can be blocked.So if I open up another terminalhere, and go ahead and try and run this, again, you see that we get our application panicking.And the reason for that is we’re trying to access a TCP port that’s already been blocked.And it’s been blocked by the fact that we’re running the application over here. So thisis a situation that happens all the time. Now, the listening serve function doesn’thave an opinion on if that’s a panicking situation or not, because he just tried to execute something.And it’s going to return an error value saying, Well, that didn’t work, it’s reasonable toassume that listening serve can fail. And so it’s not going to panic is going to returnan error. Now, we’re the ones writing the web application. And we know that if thatdoesn’t work, the entire application gets brought down, and nothing happens. So in thatsituation, we decide that we’re going to panic passing out that error that comes from thelistening serve method, letting whoever’s trying to start this up, know that somethingvery bad just happen.And so this is a common pattern that you’re going to see and go gois rarely going to set an opinion about whether an error is something that should be panickedover or not. all it’s going to do is tell you, hey, this didn’t work the way that youexpected it to work. It’s up to you, as a developer to decide whether that’s a problemor not.So in this case, we say, yeah, that is a problem, we fail to start our application.And so we do want to generate a panic. So what are we going to do in the situation thatour application is panicking. And we can get ourselves to a situation where we can recoverthe application. So panics don’t have to be fatal. They just are, if we panic all theway up to the go runtime, and the go runtime realizes wait doesn’t know what to do witha panicking application. And so it’s going to kill it. So we come back to this applicationhere, and run, we see that once again, we’re getting this panic.But something I want toshow you related to our deferred discussion is this modification here. So I’ve added thisline, a deferred print statement that says this was deferred. So if we run this application,something interesting is going to happen. We get stopped printed out. That’s not a bigsurprise. But then we get this was deferred printing out and then the panic happens. Andthis is really important, because panics happen after deferred statements are executed. Sothe order of execution is we’re going to execute our main function, then we’re going to executeany deferred statements, then we’re going to handle any panics that occur. And thenwe’re going to handle the return value. So there’s actually quite a bit that happensin a function after it exits this closing curly brace here.So why is this important?Well, the first thing that’s important is that the first statements that are going toclose resources are going to succeed even if the application panics. So if somewhereup the call stack, you recover from the panic, you don’t have to worry about resources being left out there and left open.So any deferred calls to close resources are still going to work even if a function panics.But the other thing that’s really important is if I change my deferred function here tosomething like this, now, this is a custom function. And we’re not going to talk aboutthis for a couple of videos yet. But this is important in order to talk about this.So I need to jump this ahead in the queue a little bit.So what we’re creating here is what’s calledan anonymous function. And an anonymous function is simply a function that doesn’t have a name.So nothing else can call this, this is defined at one point, and we can call it exactly onetime, these parenthesis here are making that function execute. And this is an importantthing to know about the defer statement, the first statement doesn’t take a function itself,it actually takes a function call.So you want to invoke that function, otherwise, thingsaren’t going to work properly. Now, inside of this custom function, notice that we’reusing this recover function here. So what the recover function is going to do is itwill return nil if the application isn’t panicking. But if it isn’t nil, then it’s going to returnthe error that actually is causing the application to panic. So in this logical test, we’re checkingto see if it’s not nil.So if it’s not nil, that means our application is panicking. andin this situation, we’re simply going to log that error out. Now, what happens in thissituation is the execution still stops at the panic. And let me import this log packagebefore we run this. And we see that the application still execute. So we got the string startprinted out, then we printed out the error using the long package. But we didn’t getthis end function printed out. So it looks like our application is still dead.But recovereddoes have some important impacts if we have a deeper call stack than what we’re dealingwith right here. So let me drop in this example in order to show you. So in this case, we’vegot the main function, that’s going to be our application entry point, of course. Andthen we’ve got this other function called panikkar. And all this thing does is it’sgoing to print on the line that says it’s about the panic, and then it’s going to panic.And it’s going to go ahead and recover from that panic using that deferred function thatwe saw just a moment ago, then we’re gonna have this line here, done panicking. And thenup in our main function, we’re going to print start, we’re going to call the panacur. Andthen we’re going to print and so let’s see what happens when we run this. So as you see,we get the start line printed out, like you would expect, we see the about the panic stringprint out, then we panic, something bad happened, we go into our recover loop, because we’renot going to execute this because our application panic.And so our panikkar function is goingto stop execution right there and execute any deferred functions. And inside of thatdeferred function, we call recover. So in that recover, we’re going to log out the factthat we have that error, and we’re going to log that error message out that we see here.But then in the main function execution continues. So in the event that you’re recovering froma panic, the function that actually recovers, still stops execution, because it’s in a statewhere it can no longer reliably continue to function. And so it makes sense for it tostop doing whatever it was trying to do. However, functions higher up the call stack, thosefunctions that call the function that recovered from the panic, they are still presumablyin a situation where they can continue, because you recover function said that your applicationis in a state working to continue to execute.Now, this is a little bit limiting as well,because in order to determine what that error is, you actually have to call the recoverfunction, which basically means that you’re saying that you’re going to deal with it.So what happens if you get that error, and you realize that this isn’t something thatyou can deal with? Well, in that case, what you’re going to do is repainting the application.So all we need to do in order to do that is just read through the error, or you can comeup with another error string, whatever makes sense for you. But in this case, inside ofthe handler, we’re throwing a panic again, then we actually see that we don’t get thatend statement printed out our main function panics because we read through that panic.So we get the full stack trace of when the panic actually happened.And we see that we’reinside a func one function, one is actually this anonymous function right here. And wesee that we do get that stack trace printed out and we don’t get the string and printedout. So if you’re in a situation where you’re trying to recover from a panic, and you realizeyou can’t handle it, you can feel free to re throw that panic, and the further managementof that panic, higher up the call stack.Okay, so let’s go into a summary and review whatwe’ve talked about in this video. In this video, we talked about the final two controlflow concepts that we have to be aware of in go programming. Now, one could argue thatdiffers and panics aren’t really control flow constructs, because they’re not the traditionalbranching or looping logic that we consider. But they definitely do alter the flow of executionof our program. And so I’m going to lump them together in this category. The first thingthat we talked about was the use of the defer function in order to delay the execution ofa statement until the end of a function. Now, these are useful to group open and close functionstogether. So if your open function is going to open up a resource, and you need to makesure that you close that, then you can defer the call to close that resource to make surethat you’re freeing up the memory and not holding on to that resource any longer thanyou need to.The one thing I would warn you though, is be careful loops. If you’re openingand closing a bunch of resources inside of a loop, then you probably want to explicitlyhandle that close without the deferred keyword. Because when you’re using deferred keyword,all of those resources are going to stay open until the function finishes execution. Andthat can cause you some memory issues, especially if you’re dealing with a very large numberof resources. If you’ve got multiple different statements inside of a function, then theyrun in life order or lastin. First out, so the last deferred statement that you callis going to be the first one that actually executes. And again, this makes sense, becauseif you’re opening a bunch of resources, and those resources are dependent upon one another,then you’re going to close them in the reverse order that you open them, which is typicallythe right way to go.Arguments in a deferred call are evaluated at the time the defer isexecuted, not at the time the called function is executed. And that’s important to keepin mind because you could pass in variables into a deferred function call. And it canbe a little bit confusing if you change the value of those variables further on. And thosearen’t reflected in your deferred statement. So just keep in mind, when you call defer,the value of those variables are going to be captured at the time that that defer isexecuted, not at the time the function actually executes. Now, something unplanned happensin our application, then we’ve got two ways that a go application can go it can returnan error value, which is the normal case, or it can panic. Now, what you generally wantto do is you want to return an error value, because in go programming, we typically don’tconsider a lot of things that go wrong in an application to be exceptional events, orto be events that should cause the application to shut down.For example, a classic exampleof that is making an HTTP request, and you make the request and you don’t get a responsefrom that server. Well, that’s something that happens all the time, no response is a validresponse, it just happens to be an error, because you’re looking for that resource,and you got a 404 return back. So in that case, you’re going to return an error value,you’re not going to panic, the application panics are used when an application gets intoa state that it cannot recover from, for example, you hand the runtime a divide by zero problem,there’s no way for you to figure out how to divide a number by zero, and so has no wayto manage that. And that’s a situation where the application is going to panic. So justto summarize, then, they occur when an application can’t continue at all, don’t use them whena file can’t be opened.Unless it’s a critical file. For example, if you’re opening a templatethat’s used in a web application to generate your view layer, then that might be somethingthat’s worth panicking over. But if you’re trying to open up a log file, and you can’tget there, well, there’s no reason to panic for that necessarily, you just need to returnan error value and then inform somebody that the logs aren’t available. Now a situation where you might want to panicis unrecoverable events. So if you’re starting up a web server, and it can’t get ahold ofthe TCP port that it’s supposed to be listening on, then that’s probably a situation wherepanic makes sense, the function will stop executing immediately at the point of thepanic, but the third functions will still fire. If nothing handles that panic, theneventually the panic is going to go up the call stack, it’s going to hit the go runtime,the go runtime has no built in handling for panicking situations. And so the program willthen exit. If you do have a panicking situation that you feel that you can recover from, thenyou can recover using the built in recover function.Now that function is used to recoverfrom panics, it’s only useful inside of deferred functions. And the reason for that is becauseof the behavior of panic. Remember, when an application starts to panic, it no longerexecutes the rest of that function, but it will execute deferred functions. So the properplace to use the recover keyword is inside of a deferred function, that’s going to lookfor a panicking situation. And if the application is panicking, then it can go ahead and decidewhat to do with it, the current function will not attempt to continue.But if you do recover,then higher functions in the call stack will continue as if nothing went wrong. Now, ifthat’s not the behavior that you want, if you call that recover function, you look atthe error that’s returned from the recover function and you can’t handle it. Rememberthat you can go ahead and rethrow that panic by calling the panic function again. And thenthe panic will continue to propagate up the call stack, I want to talk about pointersand how we can use them in the go language.We’ll start that discussion off by learninghow to create pointers. And then we’ll talk about something called dereferencing. a pointer,which is basically using a pointer to get at some underlying data. Then we’ll talk aboutthe new function. And then we’ll talk about a special type in NGO called nil. And thenwe’ll wrap up our discussion by talking about built in types and go that use internal pointers.And so their behaviors a little bit different than other types that you’ll work with inyour applications.Okay, so let’s dive right in and learn how to create some pointers.To start our discussion, I want to start as simply as I can. So I’m going to use thisexample here. As you can see him declaring a variable a and assigning it the value 42.And then I’m going to go ahead and print that out. So it should be no big surprise thatwhen I run this, the value 42 gets printed out.Now, if I extend this application a littlebit, and I create a variable b and assign it to the value of a and print both of thoseout, then again, it’s no big surprise that 42 prints out two times. Now since a and bare value types. When I put in this line here, what go is going to do is it’s actually goingto copy whatever data is stored in a and assign it to be. So we’re not actually pointing tothe same memory. And we can prove that by changing the value of a to, for example, 27,and then printing out everything again. And if we run this, we see that the value of achanges to 27, but the value of b stays at 42.Now we can change this behavior a littlebit by having B point to a using something called a pointer. Now in order to demonstratethat, I’m going to actually change our declaration syntax a little bit and go to more of a longform syntax. And the reason for that is to make things a little bit more clear abouthow the pointer notation works. So I hope you’ll agree with me that this line eightis exactly the same as the previous one that we had, it’s just a little bit more verbose.Now, if I want to change B into a pointer, and use that same long form syntax, what Ican do is declare the variable b. And then I’m going to declare it as a pointer to aninteger. And the way I declare it as a pointer is by preceding the type that I’m pointingto with this asterisk here. So then if I want B to point to a, then I’m going to use a specialoperator called the address of operator that you see here.So at line nine is now sayingis that B is a pointer to an integer. And I want to point it to a now what is a pointer exactly? Well, let meremove these lines here and run this and see what we get as output. So as you see here,a is still holding the value 42, like we expect, but B is holding this strange data here. Sowhat is that? Well, this is actually the numerical representation for the memory address thatis holding the location of a. So at this location in memory, we actually have assigned the integer42. So be isn’t holding the value 42, it’s holding the memory location that’s holdinghis data.And we can prove that by using the address of operator down here. And when werun this, again, we should see, in fact, we do see that the values are exactly the same.So the address of A in memory is this value here, and B is holding that exact value. Andas a matter of fact, we can even go the other way. Because while the address of operatoris going to give us the address of a variable in memory, we can use a different operatorin order to figure out what value is actually being stored at a memory location. And that’scalled the dereferencing operator. So if I go ahead and remove this, and then I’m goingto put a dereferencing operator right here in front of this pointer. Now you notice we’reusing the same asterisk. But these have a little bit different meaning here. So up hereon line nine, this asterisk before type is declaring a pointer to data of that type.So this is a pointer to an integer. Now when I put the asterisk in front of a pointer,then that’s going to dereference, which basically means it’s going to ask the go runtime, todrill through the pointer, find the memory location that that pointer is pointing to,and then pull the value back out.So if we run this, we see that we get the value 42printed out both times once again. Now what’s the point of all of this, what the point is,since B is pointing at the same value of a, Now both of these variables are actually tiedtogether. So if we change the value of a once again, and then print out their data, nowwe see that both A and dereferencing, b both give the value of 27. Because they’re bothactually pointing at the same underlying data. As a matter of fact, we can even dereferencethe pointer and use that to change the value. So if I use the dereference, B, and assignthe value 42 to it, and then print it out again, then we see that once again, both valuesare changing a and the value that B is pointing to our both teams, because it’s in fact thesame data.Now, if you come from a background in languages that allow you to work with pointersas variables, then you might be expecting to do something called pointer arithmetic.So if I drop this example in here, we’re going to start to play around with something that’sgoing to lead us to see how go treats pointer arithmetic. So I’m going to start with a variablea, and that’s going to hold an array of three values, one, two, and three. And then I’mdeclared B as a pointer to the first element in the array to this value right here. Andthen C is pointing to this second element right here. Now if I use this print statement,here, it’s going to print the value of the array and then this percent p syntax is actuallygoing to print the value of the pointer for BNC.So if we run this, we see that we doin fact, get the array and then we get these two memory locations printed out that B andC are holding. Now notice that C is holding a value that’s for higher than B. And thereason for that is how go lays out arrays in memory. Since this is an array of integersand integers in this version of the runtime are four bytes long each element of an arrayare four bytes apart. So this memory address ending with 124 is holding the first elementin the array, and then four bytes later, we’re going to hold the next element of the arrayc you might be tempted to do something like this if you come from another language, ifI take the address of C and subtract four, then that actually should give me the addressof B and then I can dereference that and Both of these should be pointing to the head ofthe array.Well, if I run this, I in fact, see that I get an error. And the reason forthat is go does not allow math like this to be done on pointers. Now, once again, if you’vecome from C or c++, you’re probably aware of the tremendous performance advantages thatyou can get if you’re allowed to do pointer arithmetic, because you can jump around mappedmemory very, very quickly, and gain some pretty substantial benefits in the performance ofcertain applications. However, whenever you get into pointer arithmetic, you’re typicallygetting into some fairly complicated code. And since go has as one of its core designconcerns simplicity, the decision was made to leave pointer arithmetic out of the golanguage.Now, if you absolutely need to have something like this in your application, thenwhat I would suggest is you can come into the go packages and come down here to theunsafe package. And this is going to give you operations that the go runtime is notgoing to check for you. So if you really need to do pointer arithmetic and things like that,then the unsafe package, which has a very appropriate name is available for you forthose very advanced scenarios. Now, those scenarios are advanced enough that what I’mgoing to suggest is if you need to know it, you’re going to learn it. But generally, you’renot going to need to know how this stuff works. Now the next thing that I want to show youis how we can actually create pointer types. So we’ve seen this address of operator andthat’s allowing us to instantiate a pointer to a certain variable.So if we look at thetype of B, it’s actually a pointer to an integer because we’re pointing to one element in thearray. But so far, we’ve had to declare the underlying type first. Well, that’s actuallynot necessary and go because often, you only want to work with the pointers, and you don’treally care where the underlying data is stored, you just need the ability to point to it whereverit’s at. So in this example, we see how we can do that. Now we’ve seen almost exactlythe same syntax before, because when we were talking about structs, we had an example thatlooks something like this. So we were declaring my struct object, we were instantiating itusing the object initialization syntax. And when we print everything out, we print thevalue 42 out. Now if I make this MSX variable, a pointer to a my struct, and then use theaddress of operator in this object initializer, then I actually get almost the same behavior,except for notice that when I print out the value of MS, I end up with this ampersandhere, which is basically saying that ns is holding the address of an object that hasa field with a value 42 in it.Now the advantage of being able to do this, it’s going to cometo light in a future video. But for now, just be aware that you can do this. Now this isn’tthe only way that we have available to us to initialize a variable to a pointer to anobject, we can also use the built in new function. Now unfortunately, with the new function,we can’t use the object initialization syntax, we’re just going to be able to initializean empty object. So if I go ahead and run this, we see that we do get an initializedobject. But all of its fields are initialized to their zero values, we can’t initializethem using the object initialization syntax. Now, since I mentioned zero values, it’s importantto understand the zero value for a pointer. Because as we talked about, in a very earlyvideo, every variable that you declare in go has an initialization value.So right hereafter line eight, ns is holding something. So the question is, what is that thing? Soif I go ahead and copy this print statement up here, we will be able to answer that question.So let me format this and run it. And then we see that we get the special value nil out.So a pointer that you don’t initialize is actually going to be an initialized for you.And it’s going to hold this value nil.So this is very important to check in your applications.Because if you’re accepting pointers as arguments, it is best practice to see if that pointeris a nil pointer. Because if it is, then you’re going to have to handle that in a differentway. So for example, if we try and drill through and get to this foo field, but and this isactually nil, then we’re going to get a runtime exception, and our program is going to crashon us. Now that actually leads us to an interesting point, how do we actually get at this underlyingfield and work with it? Well, the obvious way that we’re going to need to do that iswe’re going to have to dereference the ns pointer in order to get it that struct, andthen we can get it that field.So we’re going to have to use something like this. Now, youmight be asking why the prints are there? Well, it turns out that the dereferencingoperator actually has a lower precedence than the dot operator. So we need to print in orderto make sure that we’re dereferencing, the MS variable instead of dereferencing, Ms dotfoo. So now we can go ahead and set this to the value 42. Now in order to get at the valueof foo, to print it out, then we’re going to have to repeat the same exercise. So we’regoing to add some brands here. I’m going to wrap this ms variable, and then we’ll printout the value of foods. So if I go ahead and run this, we in fact, do set and get the value42, which is the value of that field. Now I hope you’ll agree with me at this pointthat this syntax is really ugly, because we use this syntax every time we dereferencea pointer, we’re going to have to use match that a params and have this dereference operator.Well it turns out because of the limitations that are put on point Here’s the compileris actually able to help us out a little bit.So in fact, we don’t need this syntax at all.If we go ahead and remove this and remove this from the print statement as well, andrun this, we actually get exactly the same behavior. Now again, if you’re coming froma language, which makes extensive use of pointers, this is probably freaking you out. Becausethe pointer and s doesn’t actually have a field foo on it. Thepointer MS is pointing to a structure that has a field foo. So how is this working? Well,again, this is just syntactic sugar. This is just the compiler helping us out becauseit understands or not actually trying to access the Foo field on the pointer, we’re implyingthat we want the underlying object. And so go is going to go ahead and interpret thatproperly for us, and dereference, the pointer. So the compiler really sees this statementthe same as this statement, they’re exactly the same to the compiler, it’s just one readsa little bit more cleanly. Now, the last thing that I want to talk about today is how gohandles variables when they’re assigned one to another.So let me go ahead and paste thisexample in here. As you can see, on line eight, we’re initializing an array. On line nine,we’re initializing another variable and pointing it in the same array as a, then I’m goingto print out both A and B. And then I’m going to change index one of the A array to 42,and print them out again. Now, we’ve already done this example in the past, and hopefullyyou remember that a is going to change but B is not because b is a copy of the arraythat we stored in a and so they update independently of each other. However, if I remove this index,and turn this into a slice, the behavior changes a little bit. If we run this, now we see thatboth A and B are changed together. So what happened there? Well, the slice is copiedjust like the array, but the effect of the copying is a little bit different. Becausein the version with an array, the values of the array are actually considered intrinsicto the variable. So A is holding the values of the array, as well as the size of the arrayand that size is held that way we can do bounds checking.So for example, if we asked forindex three, which is beyond the bounds of this array, and run, we can do bounds checkingin the go language. And that’s a very good thing. However, with slices, remember, a sliceis actually a projection of an underlying array. And so the slice doesn’t contain thedata itself, the slice contains a pointer to the first element that the slice is pointingto on the underlying array. So what that means is that when we work with slices, the internalrepresentation of a slice actually has a pointer to an array. So while line nine is still copyingthe slice a into the slice B, part of the data that gets copied is a pointer, not theunderlying data itself. What that basically means is, when you’re sharing slices in yourapplication, you’re actually always going to be pointing at that same underlying data.Now, the other built in type that has this behavior is a map.Because maps, once again,have a pointer to the underlying data, they don’t actually contain the underlying datain themselves. So if I take this example, where I’m initializing a map of strings tostrings and assigning that to a, and then B is assigned to a, then I print them bothout, then I change one of the values in a and print them out again, if I run this, wesee that both maps start out the same. And then when I change the key foo in the map,a we actually change that in the map B as well.So what does that mean? Well, what itmeans is, when you’re working with slices and maps in a go application, you have tobe very, very careful to keep in mind at all times who’s got access to that underlyingdata. Because passing slices and maps around in your application can get you into situationswhere data is changing in unexpected ways. However, if you’re working with the otherdata types, specifically primitives, arrays, or structs, then this generally isn’t goingto happen to you because when you copy a struct, it’s actually going to copy the entire structureunless you’re using pointers.Okay, so that wraps up what I have to talk about with pointers.Let’s head into a summary and review what we’ve talked about in this video. In thisvideo, we talked about pointers and how to use them in the go language. Now, we haven’tseen a lot of practical application for pointers yet. But we need to understand what pointersare. Before we get into that. So over the next couple of videos, we’ll get into whyyou would want to use pointers and the benefits of them. But for now, we’re just trying tointroduce the basic subject.So we started by learning how to create pointers. And welearned that if we prefix a type with an asterisk, that’s actually going to declare that typeto be a pointer to that underlying data type. So for example, we have this asterisk int,which is going to be a pointer to an integer. We also learned how we can create pointersusing the address of operator to get the address of an existing variable in memory. Then welearned about dereferencing pointers and how we can use that asterisk operator again, butthis time in front of a pointer instead of in front of a type and use that to drill throughthe pointer to get at the value that the pointer is pointing to. We also learned that whenyou’re working with complex types, such as pointers to structs those pointers are automaticallygoing to be dereferenced for us. So our syntax doesn’t get cluttered up by a whole bunchof dereference, operations and parenthesis, then we moved on to learn how to create pointersto objects. And we learned that there’s a couple of different ways.So the first thingthat we can do is use that address of operator to get access to a pointer to an object thatwe’ve already created. So in this example, we’ve got an instance of a my struct objectcalled Ms. And then we can use that address of operator to create a pointer p to thatstruct. But we can also do that directly. So if we proceed an object initializer, withthat address of operator, then we can actually directly create a pointer.And we don’t haveto have an intermediate variable that’s holding that value, we can also use the new keywordto initialize an object, but we can’t initialize the fields at the same time. So the behavioris a little bit different, because we’re going to have to use the new keyword that’s goingto zero out all the fields in a struct, for example. And then we’re going to have to comein later and initialize all the values. The last thing that we talked about was typeswith internal pointers. And we saw how while they’re treated exactly as any other variabletype, when we do an assignment, their behavior is a little bit different.So all assignmentoperations and go are copy operations. So whenever you have a variable a and you createa variable b and set it equal to a, all the data in a is going to be copied in order tocreate B. However, slices and maps contain internal pointers. And so even though they’recopying, they’re copying pointers, and so they’re pointing to the same underlying data,we’re going to take a deep dive into functions and how you can use them in the go language.Now, we’ve been talking about functions throughout this entire video series. But we’ve neverreally taken the time to focus on them, because there’s a lot of groundwork that we’ve hadto go through building up to the point where we can understand what a function is, andhow we can use those in our applications. So in today’s video, like all of our videosin this series, I’m going to break the discussion down into multiple parts. We’ll start by talkingabout the basic syntax of a function.Then we’ll talk about the parameters that you canpass into a function to influence how it works. Then we’ll talk about the return values thatyou can get back out of the function. We’ll talk about something called an anonymous function.We’ll talk about how functions in the go language are first class citizens and can be passedaround in your application like any other variable, and then we’ll wrap up our discussionby talking about a special kind of function called a method. Okay, so let’s get startedby learning the basic syntax of a function.To start our discussion of functions, we don’thave to go any farther than the basic application that the NGO playground gives us. So as soonas you come into the playground, you’re presented with this very simple application. And righthere, we have our first function. Now, the way that a go application is structured, isyou always have to have an entry point in the application. And the entry point of goapplication is always in package main. And within that main package, you have to havea function called main that takes no parameters and returns no values. So we can see thatright here.And so when we run the application, the application actually starts right here.And so we print out the string, hello playground. And that’s all that our application has todo. So every NGO application starts this way. And we see here the most basic function thatwe can create in the go language. So there are several major parts that we need to understandabout a function. First of all, they start with the func keyword. So as you can see here,we’re not going to start with function or anything else, we start with the func keyword,and that’s going to describe a function that we’re going to create.Then we have the nameof the function that we’re going to create. And this follows the same naming conventionas any other variable and go see you’re going to use Pascal case or camel case for the namesof your functions. And depending on if you have an uppercase or lowercase determinesthe visibility of that function. So just like with variables, and uppercase first letteris going to be published from the package, so anything else can use it, and a lowercasefunction name is going to be kept internal to the package. Now after the name of thefunction, we have these match params here now we’ll see as we get into parameters, whatthese are for, but this is required syntax after the main function. So even if you don’ttake any parameters in your function, you have to have these match params.And thenthe actual body of the function is contained within these curly braces here. Now thereare a lot of holy wars and a lot of languages about where these curly braces should go.So some languages put them here, some languages put them down here, some languages like toindent them, there’s all sorts of different conventions about where to put these curlybraces. Well, in the go language, there aren’t any arguments because this is the conventionthat is enforced by the compiler itself. So you have to put the opening curly brace onthe same line as the func keyword. And then the closing curly brace generally has to beon its own. Now there are a couple of situations where you can have that closing curly bracecombined with a couple of other params. And we’ll talk about that a little bit later inthis video. But generally speaking, when you’re defining a function, the closing curly bracehas to be on its own line.Now, with functions defined like this, the execution path is static,we can’t actually influence what our functions doing from the outside, because we’re notpassing any information into it. So if we do want to pass information into it, thenwe’re going to provide what are called parameters into the function. So let me just drop anexample that uses parameters. And you see here a main function is now calling into anotherfunction called say message. And that same message function takes in this parameter MSG,that’s of type string. So when you’re defining a function that takes parameters, the parametersgo between these two parenthesis here. And they’re described like any other variabledeclaration, except for you don’t need the var keyword. So you’re going to have the nameof the parameter, and you’re going to have the type of the parameter. So then when wewant to call that function, we have to pass in the value for that parameter.And that’scalled an argument. So we’re going to pass in the argument Hello, go. And then insideof our function, we’re printing out the message that gets passed in. And so when we run this,we see that Hello go prints out as a result. Now this MSG parameter isn’t special in anyother way than the fact that it’s passed into the function, it’s treated as a local variable,just like any other local variable that we might create. So if we created another variablehere, and we said, Hello, go, that’s treated exactly the same way as our mystery variable.So the only difference between the two is the MSG variable can be passed in from theoutside. And of course, that greeting variable was created locally. Now, you aren’t constrainedto just pass a single parameter in, you can actually pass multiple parameters in. So ifI drop in this example, we can see that in action.So here, I’ve extended the same messagefunction to take two parameters. So I’ve still got the message parameter that’s of type string.And then I’ve put this comma here, and I’ve added another parameter, and that’s goingto be an index. And that’s going to be of type integer here. So as you can see, we canpass as many parameters as we want, we’re just going to provide a comma delimited listof those parameter names and their types. So then when we call the function, we’re goingto pass in one value for each one of those parameters. And they have to be in the sameorder that they’re declared. So the first argument that we’re going to be passing isthe string hello, go, which is going to match this MSG variable. And then we’re going topass in the I that’s going to be the loop counter here.And that’s going to be passedinto this ID x parameter. So then, in this function, we’re just going to print out thevalue of the message and then we’re going to say what index we receive. So when we runthis, we see that the message prints out five times. And we get the same message, but theindex variable changes because we’re passing in a different value every time we call thefunction. Now, often, when you’re defining a function, you’re going to pass in multipleparameters of the same type. So you’re going to be tempted to have syntax like this. Soin this example, we’ve got a slightly different function. So instead of a generic, say, Hello,we’re going to have a say greeting function. And we’re going to provide the greeting thatwe’re going to have and the name of whoever it is we’re going to greet. So in this case,we’re passing in the string hello, and the string Stacy. So when we run this, we’re gonnasay hello to Stacey. Now, since these types are the same, the go compiler actually providesus a little bit more syntactic sugar, because this is a little bit more verbose than isstrictly necessary.So instead of specifying the type every time, we can actually justspecify a comma delimited list of variables, and then the type at the end. And what thecompiler is going to do is, it’s going to infer that every variable that’s in that commadelimited, list has the same type. So when we run this, we actually get exactly the sameexecution. But we just have a little bit more terse syntax. Now, so far, we’ve been passingparameters in as value types. If you remember from our last discussion, we were talkingabout pointers. And notice that I don’t have any pointers in our function signatures rightnow. So let me drop in this example here. And then we can start playing around withthe difference between passing in values and passing in pointers. So when I have this examplehere, and I run it, we get exactly the same output that we had before. But I’ve got somevariables that I’m using to pass in as arguments to this function. Now, what do you think isgoing to happen if I change the value of one of these variables inside the function, sofor example, if I change the name variable to Ted, and let’s go ahead and print thatout, just to verify that it printed.And then what do you think is going to happen if Iprint the same variable out, again, right here. So I’m passing in the name variableby value. So that means that the go runtime is going to copy the data that’s in this namevariable and provided to here. So what we would expect is when we change the value ofthe name variable right here, it should have an effect. And we should print 10 out here.But since this is a copy of the name variable, we actually shouldn’t have any effect outhere. So if we run this, we see that in fact, that is true. So this is a safe way to passdata into a function, you can be assured by passing by value, that the data is not goingto be changed when you pass it in. Now, if I change this to passing in pointers, by addinga pointer here, and then passing in the address of these variables right here, and then dereferencing,the pointers right here, then let’s see what’s going to happen.Actually, I need to add anotherdereference right here. And now we’re passing pointers to our variables around in our application.So now, instead of working with a copy of the name variable, we’re working with a pointerto the name variable. And so when we run this, we actually see looks like I missed a dereferenceoperation right here. And now we see that we have in fact, change the variable not onlyin the scope of the function, but in the calling scope as well. So by passing in a pointer,we have in fact manipulated that parameter that we passed in. Now, why would you wantto do this? Well, there’s a couple of reasons. First of all, a lot of times our functionsdo need to act on the parameters that are passed into them. And so passing in pointersis really the only way to do that.The other reason is passing in a pointer is often much,much more efficient than passing in a whole value. Because right now we’re passing insimple strings, and strings aren’t that large and ghost, so passing in copies versus passingin pointers is pretty much going to be the same in terms of performance. However, ifyou’re passing in a large data structure, then passing in the value of that data structureis going to cause that entire data structure to be copied every single time. So in thatcase, you might decide to pass in a pointer simply for a performance benefit. Now, youdo have to be a little careful when you’re passing in pointers, because of course, youcan inadvertently change that value. And so you can cause some issues for yourself. Now,just to remind you of something else that we talked about in the pointer discussion,if you’re working with maps or slices, then you don’t really have this option, becausesince those two types have internal pointers to their underlying data, then they’re alwaysgoing to act like you’re passing pointers in.So just be careful when you’re using thosedata structures. Because you can inadvertently change the data in your calling function,when you’re manipulating them within the calling function. The last thing that I want to talk about whenwe’re working with parameters are what are called variadic parameters. So if I drop inthis example, here, we can see an example of a variadic parameter.So in this case,I’ve got a generic some function that I’m creating here, and I’m passing in the numbersone through five. Now, I’m not receiving five variables here, instead, I’ve got one variablehere, and I’ve preceded its type with these three dots here. So what that’s done is that’stold the go runtime to take in all of the last arguments that are passed in, and wrapthem up into a slice that has the name of the variable that we have here.So then insideof the sum function, we’re going to print out what that values object is just so wecan see that and then we’re going to go ahead and add up all the values in there. So sinceit’s going to act like a slice, we can use a for loop and range over those values. Andthen we’re going to print out the result of that. So when we run this, we see that wedo in fact, have a slice is printed out, the sum is 15. So we got that result printed outproperly. And there’s no problem at all. Now, when you’re using a variadic parameter, youcan only have one and it has to be the last one. So if I, for example, want to have acustom message string, I can pass that in, and then pass that in here and then replacethis.And this still works just fine. However, I couldn’t, for example, put the message parameteras the last parameter, because the runtime doesn’t have the ability to understand wherethe variadic parameters and and where additional parameters would begin. So if you’re usingvariadic parameters, you can only have one and a half to be at the end. Okay, now, it’snice to be able to pass data into our function, because now depending on the different datathat I pass in, I can change the behavior of the function. But it’s also very usefulto be able to use our functions to do some work, and then return a result back to thecalling function. So in order to do that, we’re going to use what are called returnvalues. So if I dropped in this example, we see it’s basically the same as our last example.But instead of printing the message in the sum function, we’re returning the result out.And then the main function is actually working with that.So there’s a change we had to makein our function signature. So right here after the parameter list, and before the openingcurly brace, I’ve listed the return values type. So in this case, I’m expecting to returnan integer. So I just put it right here, inside of my function, I’m going to use the returnkeyword. And then I’m going to return the value of the variable that I’ve been buildingup throughout the course of the function. So in this case, I declare the result variablehere, I populated in this loop. And then I return that result back now up here in themain function, I can catch that return value by declaring a variable and setting it equalto the result of this function. So S is actually going to be an integer type, because that’swhat was returned out of this function.And then I can work with that integer. So if Irun this, I get exactly the same behavior that I had before. But now the sum functionis more of a pure function, it doesn’t care what I do with that result, it’s just goingto generate the result and return it back to the caller. Now another feature that gohas that’s actually pretty rare in a lot of languages, is the ability to return a localvariable as a pointer. So in our previous example, when we return that result, go actuallycopied that result to another variable, and that’s what got assigned.But we can alsodo this. So if you look here, I’m returning a pointer to an integer now. And instead ofreturning the result, I’m returning the address of the result. And so S is now a pointer.So I change to a dereference operation. So if I run this, it works exactly the same way.Now again, if you’re coming from another language that uses pointers a lot and doesn’t abstractaway the differences between working on the stack and working on the heap, then this mightfreak you out a little bit, because when we declare the result variable, it’s actuallydeclared on the execution stack of this function, which is just a special section of memorythat’s set aside for all of the operations that this function is going to be workingwith. So in this funk Exit, then execution stack is destroyed, that memory is freed up.And so in a lot of languages, this is not a safe operation, because now you’re returninga pointer to a location in memory that just got freed.And so you’ve got no idea whatvalue is going to be there. Well, in the go language, when it recognizesthat you’re returning a value that’s generated on the local stack, it’s automatically goingto promote this variable for you to be on the shared memory in the computer, what’salso called the heap memory. So you don’t have to worry about this value being cleared,the runtime is going to recognize that you’re returning a pointer from the local stack,and everything is going to work for you just fine. And that makes a lot of things moreconvenient. Because within the function, we can work with this as a true value. So wedon’t have to worry about dereferencing pointers, and then just right at the end, we can returnthe address of the result. And the runtime makes it all work for us. Another thing thatwe can do in the go language, and this isn’t done very often, but there are cases whereit is valuable is using named return values. So if I drop in this example here, noticethat I’ve changed my return value.Now I’ve got a set of parenthesis here. And then I’vegot a name for the return value and a type for it. So when you do this, this is basicallysyntactic sugar for declaring a result variable. So this variable is going to be availablein the scope of our sum function. And then that value is going to be implicitly returned.So we can work with that result variable right here within our function. And then we don’thave to specify the name of the return variable down here in line 17, we just have to tellit to return. So when we run this, we see that once again, we get exactly the same behavior.But the body of our sum function is actually quite a bit cleaner, because we don’t haveto do the maintenance of instantiating, this result variable.Now, this is actually notdone very often in the go language. And my suspicion is because it can be a little bitconfusing to read, because your return variables are declared way up here at the top of thefunction, and your actual return is down here at the bottom. So if you’re reading this code,and you’re trying to figure out what this function is actually going to return, youhave to come all the way back up to the function signature. So this can be a very valuabletechnique to use. But I would be very careful with it.Because if you’ve got long functions,the named result parameters can actually be more confusing instead of less confusing.So you have the option there, pick whichever one makes the most sense for your application.The last thing that I want to talk about with return values is the fact that we can do multiplereturn values from a function. So in order to show you why this is valuable, let’s takethis example here. So I’ve created a simple divide function that takes in two parametersA and B, that are float 64, it’s going to divide them and it’s going to return thatresult back.So if I run this, I get 1.6 666. Like you might expect, and everything’s fine.But what happens if I pass in a zero here. Now when I run this, I get an unknown result,I get a positive infinity result. And I can’t work with that in my application. So I’m goingto probably cause some sort of a failure down the line. So in a lot of languages, the onlything we could do is throw an exception or panic the application and go when we detectthat there’s this invalid value for the parameter B. So I guess we could do that we could addsome kind of logic here.If b equals equals 0.0, then we’re going to panic and we’re goingto say, cannot provide zero as second value. And that would work. But keep in mind whenwe talk about control flow and go, we don’t want to panic our application as a generalcourse of action, because panicking means the application cannot continue. Now, in fact,this application cannot continue if somebody provides the value of beat. But it’s reasonableto assume that we might pass zero in for this be parameter occasionally. So instead of doingthis, what we actually want to do is return an error back letting the calling functionknow something that they asked it to do wasn’t able to be done properly.So instead of doingthis, we’re actually going to add a second return variable. So to do that, we’re goingto add a print here. And we’re going to return an object of type error, and then close thatparenthesis off. So we can return as many values as we want from a function. But thisis a very idiomatic way of using the go language. So we’re going to return the intention ofthe function as the first return value. And then we’re going to return an error objectin case something went wrong. So in that case, what we’re going to do is, we’re going toremove this panic, because we really don’t want to be doing that.And we’re going toreturn the first value, we’re just going to zero it out, because we can’t do this operation,so we can’t return anything meaningful. And then we’re going to return an error object.Now you can generate one of those by using the air f function. And we can say cannotdivide by zero. So we’re going to provide a value for that error. And then that’s allwe need to do here. So since we’ve returned to this function in the error case, then ifwe get past it, we can continue as if our parameters are okay. And so in that case,we can actually do our operation.And then for the error value, we’re going to pass nilbecause no error was present. And again, this is very idiomatic go, we’re going to returnan error value if something went wrong, and then we’re going to explicitly return nilif nothing went wrong. And then if you’ve read any amount of go code, you’ve seen thisquite a few times. We’re going to check to see if that error also Got our standard iferror is not equal to nil, and then we’re going to put our error handling logic in here.So in this case, all we’re going to do is print out the error and return from our mainfunction. So we’re going to exit our application. If we don’t have that, then we’re going tojust print out the result of our calculation. So again, this is a very common pattern andgo inside of your functions that can generate errors, you’re going to return the expectedvalue and then an error as the second parameter, then you’re going to have a guard that’s goingto check for those error conditions, you’re going to return as soon as possible from yourfunction with the error value if an error is present.And the reason for that is we’regoing to try and left justify our code as much as possible. So we don’t end up withthese pyramids of doom, where we’re going to have else checks. And we do all of ourerror checking at the bottom, we’re going to do our error checking at the beginningand then return out as soon as possible. So if we do get past that, then we’re going tobe on our happy path. And we’re going to return out the result of a calculation and then anil error up in the calling function, we’re going to have the standard test to see iferror is not equal to nil.If it isn’t equal to nil, then we’re going to process that error,because now we’ve got something we’re going to have to deal with. And then again, we don’thave an else block here, we just continue moving on, we’re going to make sure our errorhandling logic either recovers from the error or exits onto the function. And that way,we can keep our main thread of execution left justified.So our main thread of executionhere is we’re going to call this divide function, and then we’re going to print out the result.So any error handling should not force the main line of execution to be indented. Sonow if we run this, we see that I forgot to initialize my error parameter. So let’s goahead and add that. And this is something else I should talk about. When we’re receivingmultiple values out of a function call, we actually have a common delimited list of thosereturn values.So this D parameter is going to match up to this float 64. And this eerrparameter is going to match up to this error parameter here. So now if I run, everythingshould work. And we see that we now get an error cannot divide by zero. So our main functiondoesn’t explode on us, we actually have something that we can work with. But if we put in avalid value, then we’re on that other path of execution, and we get the return valueback out.Now, so far, we’ve been treating functions as this special thing, because we’realways using this func keyword, we’re declaring these at the top level of our application,we’re working with them. But functions and go are actually more powerful than that. Becausefunctions themselves can be treated as types, they can be passed around as variables, theycan be passed as arguments into functions, you can get them as return values, prettymuch anything you can do with any other type you can do with functions. So let’s take alook at that a little bit. So in this example, I’m actually declaring a function on the fly.And this is called an anonymous function. Now we’re going to continue to explore thisover the next couple of minutes.But this is the simplest example I can come up with.So notice that I’m starting with the func keyword, I’ve got the params. For the parameters,I’ve got the opening and closing curly brace, but I don’t have the function name here. Sowhen you’re doing this, this is what’s called an anonymous function. And this is the basicstructure of a function when you’re not working with functions in this traditional scope.But instead you’re working with functions as types. So inside of my function body, I’mprinting out the message Hello, go. And then I’ve got accompanying my closing curly brace,these params here. Now these params here are basically going to invoke this function.Sothis is an immediately invoked function, I’m defining it and executing it at exactly thesame time. So when I run this, and actually does execute that function, and we get thevalue Hello, go printed out. If I don’t have these friends, then the compiler is a littleconfused. It doesn’t know what to do with this function.It’s just defined, but it’snever used anywhere. So fails a compilation check. But if I do invoke that function immediately,then I get this behavior here. Now why would you use an anonymous function like this, Iactually have no idea why you would use an anonymous function like this. I mean, therecan be situations where you can declare variables inside of here. So if I declare a messagevariable here, and I set that equal to this string, and then print that out, that canbe valuable because you’re actually generating an isolated scope. So this message variableis not going to be available in the main function is only going to be inside of this anonymousfunction here. Now another place that you might use this is if we’ve got a for loop.So if I start up a simple for loop, and I’ll just count up to five, and increment by one,let’s see if I can do this on the fly here. And then I come in here and I actually printthe value of i out, I’ll get rid of this message here and I’ll print out I, you’re going toget a little bit of strange behavior.If I run this, this works, okay. But as we startgetting into asynchronous code, things are going to start behaving a little bit oddly.So we do have access to this AI variable, because we’re in the scope and the main function.And so inner functions can actually take advantage of variables that are in the outer scope.But the problem is, if this function is actually executing asynchronously, then this countervariable is going to keep going. And we may actually have odd behavior here.So the bestpractice is actually to provide a variable inside of here and actually pass that AI variable.And what that’s going to do is we’re not going to be reading from the outer scope anymore.We’re going to be passing that into the function execute And that way, even if this is runningasynchronously, we’re going to print out the value correctly. Now, this works correctlyin the playground, the way that we have this right now, because we actually aren’t doinganything asynchronously. This is all synchronous execution. And so we are safe to use thisouter counter. But it’s not good practice to do that. Instead, it is best practice topass in that kind of variable. If you need that in your inner function. That way, changesin the outer scope aren’t reflected on the inner scope. Now taking this a little bitfarther, we can work with functions as variables, like I said before, so in this case, I’vedeclared an anonymous function, and I’ve assigned it to this variable F.And then I can executef by just invoking it like any other function. So if I call that, we see that we do printhello, go out. So now that I’ve got this function defined as a variable, it’s free to pass aroundmy application. Now, you might ask yourself, what is the signature for this function. Solet’s go ahead and go through that. So if I get rid of the short syntax and extend thisout a little bit, then I’m going to start with the var keyword. And since this is avery simple function, the type is just like this, we have the func keyword, and then anopen and close parenthesis. So the parameter is normally going here, I don’t have any parametershere, I don’t have any return types. So the type signature for this variable is simplyfunc with two params.There. So if I run this, that works just fine. Now we can go a littlebit more complicated. And I’ll drop an example of that in just to show you how that’s goingto look. So in this case, I’m declaring a function signature for a divide function,that’s going to take in two floats, and it’s going to return a float and an error. Andyou see, this is the syntax for that. So we pass our parameter types in here. And thenwe have the return types in params. As well, if you have just a single return type, thenyou don’t need these params, we could just put the type there like that.But we do havethat error type this coming back. So we do need to include that. And then when I initializethat variable, I’m going to set it equal to an anonymous function that takes a and d.And this is exactly the same divide function that we had before. And I can call that exactlylike we had before. So when I run this, it has exactly the same behavior as the lastexample we did with the divide function. But now we have the divide function declared asa variable. And we’re working with it exactly the same way as when we declared it as a function.Now, the difference between this and when we had the divide function declared globally,is if I try and call it up here and run the application, notice that I get an error becausein this case, the function divide hasn’t been declared yet, because it’s declared as a variable.And so I can’t work with it yet.So that’s just something to be aware of. If you’re goingto be working with functions as variables like this, make sure that they’re definedbefore you actually try and execute them. Okay, the last thing that I want to talk aboutwith functions today is working with what are called methods. And there’s a couple ofthings to talk about with those. So let me just drop in an example that shows that.Andwe can walk through this and then see what it’s going to do. So in this example, I’vegot a struct called greeter that greeter struct has two fields greeting and name. And thenI’ve got this method on it. And we’ll come back to this in a second. So in my main function,I’m declaring a greeter struct, and then I’m calling this function preceding it with thestruct that I have here. And this is how we’re going to do method invocation. So we callthe method just like we were accessing a field, except for we have the params here where wecan pass some arguments in. Now my method declaration down here looks a lot like a functionexcept for it’s got this odd bit right here. And this is what makes this function intoa method. So a method is basically just a function that’s executing in unknown context,and unknown context.And go is any type. Now it’s very common that we can use structs.But you can use any type. So we can make a type for an integer. So maybe we have a typefor an integer called counter. And then we can add methods on to that counter type, andwork with those. So when we declare that method, we’re actually going to get access to thattype right here in this part. So what’s going to happen when we call the greet method isthe greet method is going to get a copy of the greeter object. And that’s going to begiven the name g in the context of this method. So then when we print out, we can access thefields on that greeter object. So we can print out the greeting and the name.So when wego ahead and run this, we see that we get Hello go printed out. And that’s the basicsof a method. So methods are basically the same as functions, they just have this littlebit of syntactic sugar, that’s providing a context that that function is executing in.And when we do that, we call that a method.Now when we use this syntax right here, noticethat we’re specifying greeter as a value type, we don’t have a pointer here. So this is what’scalled a value receiver. The received object in this greet method is the value greeter.So what that means is just like any other time that we’re working with values, we aregetting a copy of the struct, we’re not actually going to get the struct itself.So if I changethe value of the Name field here, and then I print the Name field out of here, so I saythe new name is and then I print the Name field out, then it’s no big surprise thateven though I assigned an empty string to the Name field here, up here in the main function,it didn’t have any effect. Because down here in this method, we’re operating on a copyof the greeter object. We’re not operating on the greeter object itself. So again, that’svery valuable if you want your methods to be able to access the data of their parenttype without being able to manipulate Just keep in mind there is a cost with that. Soif there’s greeter object was a very large struck, then we would be creating a copy ofthat struct every time we invoke this method.Now, as you might expect, there’s anotheroption that we have here. And that is to pass in what’s called a pointer receiver. So ifwe make this a pointer, and run the application, again, now we’re actually able to manipulatethat underlying data. So we’re going to print out Hello ghosts. So the method operates inexactly the same way. And we don’t have to change the format here, because we do havethat implicit dereferencing of pointers that’s working for us. But now when I change thevalue of the Name field, and print the Name field out up here, we do in fact, see thatwe’ve been able to reassign the value of that field. Okay, so that covers working with functionsin the go language. Let’s go into a summary and review what we’ve talked about. In thisvideo, we talked about functions and how to use them in the go language. And we startedout by talking about the basic syntax of a function, and we saw that this is about assimple of a function as we can get.So we start with the func keyword, we have a namefor that function. And again, if that first letter is uppercase, then that function isgoing to be published and allowed to be executed from outside of the package. But with a lowercasefirst letter, it’s going to be kept internal to the package, then we follow with a matchset of parenthesis, and then we have an open and closed curly brace. Now the open curlybrace has to be on the same line as the func keyword. And the closed curly brace has tobe on its own line after the final statement of the function, then we moved on to talkabout parameters and parameters allow us to pass data into the function to influence howthat function executes, basically providing some variables for the function that are passedin from the outside. So we talked about how parameters are passed in as a common delimitedlist of the name of the parameter and the type of the parameter.So we see here we’repassing into the Foo function, two parameters, the bar parameter that says type string, andthe bass parameter that’s of type integer parameters of the same type can be comma delimited.And the type can be listed at the end there. So in this case, we’re passing in bar andBabs as parameters. And both of those are going to be of type integer. When pointers are passed in the function containsthe value in the caller. So by default, we’re going to be passing in the values themselves.And so the go runtime is going to be copying that data and passing it into the function.So any changes that are made inside of the function aren’t going to be reflected in thecolor scope. However, if you pass in a pointer, then you are going to be able to manipulatethe value inside of your function. And that will have an effect in the calling scope.So the only exception to this rule is when you’re working with slices and maps, sincethey work with internal pointers, any changes inside of the function to the underlying datais always going to be reflected inside of the calling scope.We also talked about howyou can use variadic parameters to send a list of the same types in, so it must be thelast parameter in the parameter list. It’s received inside of the function as a slice.And you see an example of the syntax right here. So we’ve got the function foo. It hasone parameter bar that’s of type string, and then a parameter Baz, that’s a very atticparameter of integers. So inside of this food function, we’re going to have a slice calledBaz. And that’s going to contain all of the integers that have been passed in. Once yourfunction finishes doing its work, a lot of times we want it to return a value back out.And in order to get that information back out, we’re going to use return values. Soif you have a single return value, all you need to do is list the type.So in this case,our foo function needs to return an integer, we can also specify multiple return values.So if we’re going to do that, we need to put parentheses around the types that we’re goingto be returning. So in this example, we’re going to be returning an integer and an error.And this is a very common pattern that you’re going to see in NGO applications where we’regoing to have our functions return the intended value, and then an error value that’s goingto let the caller know if anything went wrong. That way, the function itself doesn’t haveto determine whether the application needs to panic, or execution can’t continue.Itjust knows it wasn’t able to do what it was asked to do. And then it can delegate whatthat error means to the application to the calling function, you can also use named returnvalues. So when you do that, instead of just providing the types in the return last, you’regoing to provide the name of that return value. So when you do that, the runtime is goingto initialize that value for you to the zero value for that variable. And when you usethe return keyword, all you need to do is enter return on its own go is going to findthe current value of those returned variables. And that’s what’s going to be returned outof your function.Another special behavior of go is you can actually return the addressesand local variables as return values, and those are going to be treated properly. Sowhen you do that those variables are automatically promoted from local memory or stack memoryup into shared memory or heap memory. So you don’t have to worry about those values beingcleared out as the function stack memory is reclaimed. We then started talking about anonymousfunctions. And we talked about a couple of different uses for those. So we have thisimmediately invoked function, which really isn’t used too often in the go language, butit’s as simple of an anonymous function as I could get.The only potential advantagethat you have here is you can create an inner scope. So local variables that are createdinside of this anonymous function aren’t going to be available outside, but I haven’t seenthat very often. It’s not going to be very often that you’re going need to use this kindof a function, then we also talked about how we can take that anonymous function and actuallyassign that to a variable. So in this example, we’ve got the variable a assigned to the valueof that function.And then we can invoke the a function just like any other function. Theonly difference between this and the normal declaration of a function is that the a functioncan only be invoked after it’s been declared. So when you declare a function using the traditionalsyntax, it’s actually declared at the time that the package is initialized. And so it’salways available to you. When you’re using this syntax, you have to make sure that ais initialized before you can call it extending on that discussion about the ability to assignfunctions to variables, functions, or types, just like any other type in go language, anytimeyou can use a primitive or a slice or an array or a map, you can use a function.So you canassign them to variables, you can use them as arguments, they can even be returned valuesfrom functions, then we also talked about how since a function is a type, we have tohave the ability to create a type signature. So if you’re declaring anonymous functions,it’s often most convenient just to use that colon equals syntax and declare your anonymousfunction and the type is going to be inferred. However, if you’re using a function as a parameterto another function, or the return value from a function, then you’re going to need to specifythat type signature. So we see an example here. In this case, we’ve got the definitionof a function f. And that function is going to take three parameters, two strings, andan integer. And then it’s going to return an integer and an error type.So it’s basicallythe same as when you’re declaring a function normally, the only difference is we don’thave the names for those variables. Because those names will be provided when we actuallyimplement the function, we just need to know the types that are coming in, and the typesthat are coming out at this point. The last thing we talked about were methods, and howmethod is a special type of function that executes in the context of a type.Now a typedoesn’t have to be a struct. Although that definitely is a very common use case for methods,you can actually attach a method to any custom type. So you can create a type of an integer,and then you can add methods on to that integer. When we create a method, we’re going to usea modified version of the basic function syntax. So before the name of the function, and afterthe func keyword, we’re going to provide another set of parentheses, we’re going to providea local name for the type that’s going to receive that method. And then we’re goingto follow that with that method type. Now, that variable is what’s called the receiverfor the method. So in this case, our G variable is what’s called a value receiver, which meanswe’re going to get a copy of that greeter object.And that’s going to be passed intothe greet method. However, we can also use what are called pointer receivers. So by addingan asterisk in front of that greeter type, the method is going to change. So insteadof passing a copy of the greeter, we’re going to get a pointer to the greeter object inthere. And then any manipulations we make to the greeter object in the greet methodare going to be reflected throughout your application. Now, that’s very powerful ifyou need the method to be able to manipulate the state of the object. It’s also much moreefficient if you’re dealing with large structures, because instead of copying the entire structure,it only has to copy a pointer.And that’s normally a much more efficient operation,I want to talk about one of the coolest features of the go language. And that is interfaces.Now I know that interfaces are normally considered pretty humble features, and they sit in thebackground. It’s much more fun to talk about go routines and channels, especially whenyou’re learning to go language. But I would argue that the way interfaces are implementedin the go language are potentially one of the reasons why go applications tend to beas maintainable and scalable as they have proven to be. So we’re going to start thisconversation like we start every conversation by introducing the basics. So we’ll learnwhat an interface is and how to use them in the language itself. Then we’ll move on todiscuss how to compose interfaces together. Now, just like in other high level languages,such as Java, or C sharp, we can actually make interfaces of interfaces.And we’ll talkabout how to do that, and why that’s a very good thing to do when you’re writing yourapplications. Then we’ll talk about type conversion. Now, we’ve touched on this a little bit beforein a previous video. But when we talk about interfaces, things changed a little bit, andit’s worth revisiting the topic. Along the way, we’re going to talk about the empty interface,which is a very useful general construct that we’re going to deal with in our programming.We’ll also revisit type switches, which we’ve talked about before, and we’ll revisit themin the context of our interface discussion. Then we’ll talk about how to implement interfaces.And there’s actually two different ways that you can do that. One is by implementing withvalue type, and one is by implementing with a pointer. And we’ll talk about some of thesubtle differences that you’re going to run into as you implement interfaces with thesetwo different types. And then finally, we’re going to talk about some best practices thathave been discovered over the last few years of working with the go language about howto use interfaces in your actual production applications.Okay, so let’s get started bylearning the basics of using interfaces in go. So to start our discussion about interfaces,I’m going to actually build our first application up a piece at a time now often I just dropin code and talk about it. But I want to take this one step at a time so that we’re workingtogether and understanding what’s going on. So the first thing that we’re going to dois we’re going to introduce our first interface. So interfaces are a type, just like structsor type aliases. So we’re going to start with the type keyword, then we’re going to enterthe name of our interface. And then the type that we’re creating is a type interface. Andthen we’re going to surround the definition of this interface with curly braces, justlike we do when we’re defining a struct.Now with a struct, we would add in here, the datathat we want that struct to hold on to because structs are ultimately data containers. Andso that’s how we work with them. interfaces don’t describe data, interfaces describe behaviors.So instead of entering a bunch of data types that we’re going to be storing inside of awriter interface here, we’re actually going to be storing method definitions. So I wantto create a write method here. And this is actually an interface from the IO package,we’re just going to be working with it here as if we created it. But this is exactly thesame interface that you would find in the IO package under the writer interface.Sothis method is going to accept a slice of bytes. And then it’s going to return an integerand an error. Now on the writer interface, the way this works is anything that implementsthis interface is going to take in that slice of bytes, write it to something that somethingmight be the console, it might be a TCP connection, it might be the file system, we don’t know,we just know that we’re writing a slice of bytes to something. And then the integer anderror that get returned, of course, the error is there in case something goes wrong withthe write operation. And the integer is normally the number of bytes written. So now that wehave the interface defined, let’s go ahead and implement it. So we’re going to implementthis with a console writer implementation, and that’ll be a struct. And that’s all weneed to do with the struct definition. Now, if you come from another language, you mightbe looking for an implements keyword or something like that.Well, in go, we don’t actuallyexplicitly implement interfaces, we’re going to implicitly implement the interface. Andwe’re going to do that by actually creating a method on our console writer that has thesignature of a writer interface. So let me just drop that in. Because if I try and typeall this out, I will screw it up, and then I’ll have bugs that I have to go through.So it’s much easier just to drop it in. But notice what I’ve done here, I’ve got a methodon my console writer called write. So it’s got the same name as my writer interface,it’s accepting a slice of bytes, and it’s returning an integer and an error. Now theimplementation is whatever I want it to be. Now, in this case, all I’m going to do isconvert that byte slice into a string and printed onto the console to keep things easyin the playground. But I can have my writer do whatever I want. So what’s the value of doing this? Well, thevalue of doing this is up in my main method, I can actually create a variable that’s oftype writer.And let me just drop that code in and format it and set that equal to a consolewriter instance. So the W variable here is holding a writer, which is something thatimplements the writer interface. I don’t actually know the concrete type, though. So when Icall the write method down here on line nine, I know how to call that because that’s definedby the interface. But I don’t actually know in my main function, what’s being writtento, that’s the responsibility of the actual implementation. So I could replace this witha TCP writer, I could replace it with a file writer, I could replace it with any otherkind of writer. And so I get what’s called a polymorphic behavior. Why nine doesn’t carewhat it’s writing to, I specify that behavior before that.But then anything that’s goingto use this w object just knows that it can write to it. And so it can take advantageof that behavior. So if I go ahead and run this application, you see that I do get alogo printed out to the console, just like I would expect. So the key takeaway here aswe’re learning the basics of interfaces, is this concept of implicit implementation. Andso what that means, for example, is if you need to wrap a concrete type, and somebodyhasn’t published an interface, you can actually create an interface that their type implements.So we did it the other way, we created an interface, and then we created a concretetype that implemented it. But there’s nothing to say we can’t go the other way around.Wecould, for example, go to if I travel to go lang.org, and go into packages, this is actuallysomething that I just ran into, in order to test SQL database connections. So if I comedown to the database package, and go into the SQL package, if we look at this, noticethat the DB type is a struct. So we don’t have an interface here. So if our go applicationis talking to a SQL database, we’ve got concrete types all over the place. So for our transactions,we’re interacting with this DB object. everything that we’re doing sending SQL statements makingqueries are all through this concrete DB object. So how do I test that without a database?Well, the way that you test that without a database is you actually create an interfacethat replicates this method signature, and the DB object from the SQL package will automaticallyimplement it, so I don’t have to worry about creating inner phases at design time if Idon’t need them myself, because consumers of my library or whatever I’m creating canalways create interfaces later.And their interfaces can be shaped to exactly what theyneed for their application. Now another thing that I want to talk about before I move onhere is a naming convention. Now obviously, the name of the interface should representwhat that interface is going to be doing for you. And there is one special case, if you’vegot single method interfaces, which are very common in the go language, then the conventionis to name the interface with the method name plus er. So if we’re defining an interface,like we have here with the right method, then the interface name should be writer, if we’regoing to create an interface with a read method on it, then the interface name should be areader. Now if you got more than one method in the interface, things can get a littlebit more challenging. But at the end of the day, you should name your interface by whatit does. And in the case of a single method interface, just add er onto the end of themethod name. Okay, now, in this example, we use the struct, which is probably one of themost common ways to implement interfaces, but you don’t need to any type that can havea method associated with it can implement an interface.And as we’ve talked about before,any type can have methods associated with it. So in order to demonstrate that, let mejust drop in this example here. Now in line 16, through 18, I’ve defined a new interfacecalled incrementer. And that increment is going to be a method that only returns aninteger, so it’s going to increment something. So whatever we’re going to implement thisthing with, is going to increment values.So down here on line 20, I defined the typealias for an integer called an int counter. And then I added a method to that custom typeon lines 22 through 25. And that’s going to be my implementation for the incrementer interface.So the method name is called increment, and it’s going to return an integer. Now, in thiscase, look at what I’m doing, I’m actually incrementing. The type itself, since I’vegot a type alias for an integer, it’s a number, so I can go ahead and increment that. Andthen I’m going to return it as the result of this method call. So I’ve actually got a type defined on aninteger, and the integer itself is storing the data that the method is using. So up herein my main function, I’m going to go ahead and create that integer counter. And I haveto cast an integer to an encounter.In order to do that. That’s what I’m doing here online eight. And then I create my incrementer and assign that to a pointer of the my nsobject. And we’ll talk about why that has to be a pointer toward the end of this video.And then I’m just going to loop from zero to nine. And I’m going to print out the valueof the increment method every time I call it. So if I go ahead and run this, I see nobig surprise, I get the values one through 10 printed out. So what’s the takeaway here?Well, you don’t have to use structs. To implement interfaces, you can use any kind of customtype.Now I couldn’t add a method directly to the entity type. Because the event typeisn’t under my control that’s defined in another package. It’s a matter of fact, that’s a primitivetype, and you can’t modify it. But any type that I do have control over that I can create,I can add methods to it. And if I can add methods to it, I can implement interfaceswith it. Now the next thing that I want to talk about is how to compose interfaces together.Because this is another very powerful concept in the go language, and is one of the keysto scalability, because if you remember I mentioned a little while ago, single methodinterfaces are very common and very powerful in the language, because they define a veryspecific behavior. But by having a single method, they don’t have a lot of opinions.And so they can be implemented in a lot of ways. So for example, the IO dot writer interfaceis one of the most common interfaces in the entire go language, because all it does istalk about how to write two things.And we write two things all the time. So by takingas little opinion as possible, we actually make the interface very, very powerful andvery, very useful. So let me go ahead and paste this example here. Because what happensif we need more than one method, but we can decompose the interfaces down. So in thiscase, I’ve created an interface that’s composed of other interfaces. So I’ve got my writerinterface that we started the video with. And then I’ve added this closer interfacethat just has a closed method on it, and returns an errorjust in case something happened when we tried to call this method.Now the writer closerinterface is actually composed of the writer interface and the closer interface. And thisis done exactly the same way that you do embedding with structs. We’re just embedding interfaceswithin other interfaces. So the writer closer is going to be implemented. If an object hasthis method on it, and this method on it, then we can treat that as a writer closer.So as an example, I’ve created this struct here, a buffered writer closer. Now, I’m notsaying that this is an efficient way of doing things. This is just an example of how youmight use this writer closer interface in a way that runs in the playground easily.So in this case, I’ve got my write method that I’m going to be implementing. And whatI decided to do is I’m going to write out whatever gets sent into the buffered writercloser. I’m going to print that out to the console in eight increments. So that’s whatall this code is doing, when you pass data into the write method, it’s going to storethat in this internal buffer that the structure defines.And then as long as the buffer hasmore than eight characters, it’s going to go ahead and write that out. But it won’twrite anything out if it’s got less than eight characters. So we’re basically buffering thedata that we’re sending in. And then down here in the close method, I’ve got to implementthat too. And so what we’re gonna do there is we’re going to flush the rest of the buffer.So I’m pulling the next eight characters out.And I’m going to write that out to the console.And keep doing that until the buffer is empty. Okay, up here in the main method, I simplycreate a writer closer variable, and define that using the new buffered writer closerfunction. And just to show you that I didn’t talk about it, that’s down here at the bottom,that’s just a constructor function that’s returning a pointer to a buffered writer closer.And I need to do that because I need to initialize this internal buffer to a new buffer. So Ihave a constructor method there just to make sure that everything has been initializedproperly.So if I come back up to the main function, and look at that, then I’m goingto call the right method. And I’m converting the string hello youtube listeners, this isa test over to a byte slice, because that’s what the right method expects. And then I’mgoing to call the close method. So if I go ahead and run this, you see that I get themessage printed out to the console in eight character chunks.And eventually I get allthis printed out. But if I comment out this last method, call here, you see that I don’tget the a test part of the string, because that’s actually a partial. And so we didn’tget that full eight characters that’s required for the right method to print it out. Andso I didn’t actually flush the buffer. Okay. So I know that maybe a little bit of a complicatedexample, to show a fairly simple thing.But I just wanted to show you this is how youcan compose interfaces together. And as long as you implement all of the methods on theembedded interfaces, then you actually implement the composed interface as well. The next examplethat I want to talk about is how we can do type conversion. So I’m going to go aheadand replace my main function here with this code here, get rid of the extra curly brace,actually, I’m going to get rid of this too, I guess I pulled in the whole function signature.And then I made a little bit of a change down here in line 13. So lines nine through 11are our original implementation, where we’re creating the new buffered writer closer orwriting a string out, and then we’re calling the close method on it.But on line 13, I’mactually doing a type conversion. So using this syntax here, where I’ve got an object,dot, and then in parentheses, I’ve got a type that I’m going to try and convert this variableto. And then I can assign that to a variable such as this PwC variable right here. Now,if that succeeds, then everything’s fine. And I can go ahead and work with it. Now,there’s nothing useful I can do with this. But I’m just printing out the variable, becauseI have to use the variables and go. So I’m just going to go ahead and print that out.So if I run this, I see I get exactly the same output I had before. But now I get thememory address of this buffered writer closer, so that tape conversion succeeded.And thereforeI can work with this no longer as a writer closer, but as a buffered writer closer. Sofor example, if I needed to access the buffer directly, then I would be able to do thatnow. Whereas with the writer closer, it’s not aware of the internal fields of a specificimplementation. And so I wouldn’t have access to that data. Now there is a problem. However,if I import the IO package, and try and convert this to a type that it doesn’t implement.So for example, if I try and convert this over to an IO reader, which is another interface,and that IO reader interface requires a read method on it.So if I try that now, let’sgo ahead and run that. And we see here we put the application into a state that it can’tmanage. And so what it does is whatever good go program does, when it can’t figure outwhat to do it panics. And the panic messages interface conversion, it can’t figure outhow to cast a buffered writer closer into an IO reader. And so it’s going to fail onus. Now, it does give us some useful information about why it couldn’t do that. It says it’smissing a method read. And then it’s gonna give us a stack trace letting us know wherethat error occurred. Now, this isn’t really great, because sometimes we need to try andconvert an interface into something else. And we’re not sure if it’s going to work ornot.So it’s not going to be good for our application to be panicking all the time,because then we’re going to have recovers and we’re going to be using that as a primarycontrol flow concept. And we want to avoid that in the go language, because panickingis pretty expensive. So we need another way around it. Well, we just so happen have anotherway around it.And so I’m going to show you that. All we need to do let me rename thisvariable, because PwC doesn’t make sense for a reader anymore. I’m going to paste thiscode in. So I’m going to now try and cast it to a variable called R. I’m going to dothe same type conversion, but now I’m using this comma, okay, syntax. So we’ve seen thisbefore, when we were trying to pull a value out of a map and we weren’t sure if it wasthere or not. Well, we have the same ability with type conversion. If we add a comma, okay,this is going to be a Boolean result. And then we can test against that to see if wecan work with it. So if the conversion succeeds, then we’re going to get an okay value backout. If the conversion fails, then we’re Going to get the zero value of whatever type wewere trying to convert to. So an IO reader is an interface.And so it’s zero value isgoing to be nil. So if we go ahead and run this now, we see that our conversion failed,but our application didn’t crash. If we switch this back to a pointer to a buffered writercloser, let me go ahead and drop that in. And we run that we got to drop out our packagehere that we’re no longer using. And then we see that we’re back to having things successfullyconverted. And we could work with that however we needed to. So this is really importantto be aware of, especially if you’re not sure if you’re going to get a pointer or a valuetype.So for example, it would be really easy to write this and have a problem because weimplemented the interface with a pointer, not with the value itself. And so we can’tactually do the conversion to the underlying value type. So let’s go ahead and run thisagain, we see that that all works. And one more thing I want to show you let me justpull this error back up again, you’ll notice that the reason this type assertion failedis because buffered writer closer does not implement writer closer now that might seema little strange to you, because our buffered writer closer has a write method, and it hasa closed method, and they have the right signature.So for some reason this works when I askedit to convert it to a pointer, but it doesn’t work when I asked it to convert it to theunderlying value. Now we’ll come back in just a second and talk about why that happens.But I want to finish our discussion of type conversions first. So stay tuned, and we’lltalk about why that works the way it does. So the next thing that I want to talk aboutis something called the empty interface. Now the empty interface is exactly that. It’san interface that has no methods on it. And we describe that using this syntax here. Now,this isn’t a special symbol, this is just an interface that we’re defining on the fly,and we don’t have any methods on it.So it’s called the empty interface. But there’s nothingspecial about it, we could create this as the empty interface exactly the same way byjust deleting the method out. And that’s an empty interface now, so you see it like thisall the time. Just be aware, there’s nothing special about this, it’s just an interfaceto find on the fly that has no methods on it. Now the nice thing about the empty interfaceis everything can be cast into an object that has no methods on it even primitives because,well, an integer has no methods. And so it can be cast to the empty interface. And sothis can be very useful in situations where you’ve got multiple things that you need tobe working with. But they aren’t tight compatible with one another. And you need to apply somelogic later to figure out exactly what you received. But we do have a problem with theempty interface.Because we now have this my object variable that’s defined as an emptyinterface, we can’t actually do anything with it, because my object has no methods thatit exposes because it’s an empty interface. So in order to do anything useful with a variablethat has the type of an empty interface, you’re going to need to do either type conversion,or you’re going to need to start using the reflect package in order to figure out whatkind of an object you’re dealing with. So in this case, on line 10, I’m actually tryingto type cast into a writer closer, and I’m using the comma okay syntax to see if thatworked. If it does, then go ahead and call the write and close methods like I saw before.And then I’ve got this other type conversion that I’ve done that before just to keep thingsconsistent.So if I run this, we see that I forgot to re import the IO package, letme go ahead and pull that back in. And we see that everything works as normal.So the empty interface is very common. But just keep in mind, it’s almost always goingto be an intermediate step. And you’re going to define a variable of the type empty interface.And then you’re gonna have to figure out exactly what you receive before you can do anythinguseful with it. The last thing that I want to talk about in the context of type conversionsare type switches. So I want to revisit that conversation from a few videos ago. And justto show you, we can do something like this. So in line eight, I’ve got a variable i that’sdefined as the empty interface, and I’m setting it equal to the integer zero.And then I’mgoing to use this switch block here, and I’m going to use this syntax. So I’ve got my variablename I, and then I’m going to use this dot and inside of prims, I’m going to put type.And so what this is called is this is called a type switch. So each of the cases in thistype of switch are actually going to be a data type. So in this case, I’m looking tosee if I’ve got an integer or a string, or I’ve got a default case, which is going tobe handled by our application, just saying it doesn’t know what AI is. So let’s go aheadand run this, I properly identify as an integer. So we execute this case here. If I put paramsaround this, then of course, I is now going to contain a string.And so if I run that,again, it identifies it as a string. And if I change this, once again, maybe we can makethis a Boolean, gotta spell true correctly, and run that then it has no idea what it is.So this is commonly paired with the empty interface in order to list out the types thatyou’re expecting to receive. And then you would add in the logic of how to process thosedifferent types. Now, I promised you that we would come back and talk about that weirdtype conversion behavior, where we could convert our writer closer into a pointer to a bufferedwriter closer but Couldn’t convert it into the value itself. So now I want to go throughand have that conversation about why that happened.So let me just drop this code in.This is a much simpler implementation than what we had before. I’ve actually not reallyimplemented these methods anymore, in order to keep things as clean as possible for youto see. So all I’m doing is I’m going to create a my writer closer, and that’s down here asmy writer closer struct with nil implementations for the methods. But I do have the methodsimplemented. So I can create this object as a writer closer, and then I’m just printingout the value of the variable just so we have some use for that variable.So the go runtimewill actually compile and run this, and the interface for the writer closers to find exactlythe way we had before. So if I run this, everything works out just fine. However, what happensif I change the receiver of one of these methods to a pointer? Well, if I run this, now, Iget an error. And the reason that I get that error is it can no longer convert my writercloser into a writer closer interface. And it gives us an interesting message here, itsays my writer closer does not implement writer closer, the right method has a pointer receiver.And this is the key to understand what happened with this. So when we define types, and weassign methods to them, each one of those types has what’s called a method set.Nowwhen you’re working with the types directly, the method set is all of the methods regardlessof the receiver types associated with that type. With interfaces, however, things changea little bit when I implement an interface with the concrete value. So notice here I’mcreating my writer closer, I’m not taking the address of my writer closer, I’m usingmy writer closer directly. So WC is defined as holding the value my writer closer. Sothe method set for a value when we’re talking in the context of an interface is any methodthat has a value as the receiver. So the reason we’re not implementing writer closer is becausea write method no longer has a value receiver, it’s going to point a receiver. And so itsmethod set is incomplete. And now we can fix this by using the address of operator andrunning again.And notice now everything works. And the reason for that is the method setfor a pointer is the sum of all of the value receiver methods, and all of the pointer receivermethods. So let’s go through that. Again, when I’m implementing an interface, if I usea value type, the methods that implement the interface have to all have value receivers.If I’m implementing the interface with a pointer, then I just have to have the methods there,regardless of the receiver type.So the method set for a value type is the set of all methodsthat have value receivers. But the method set for a pointer type is all of the methodswith value receivers, as well as all of the methods with pointer receivers. So there’sa couple of ways that we could fix this. Now in this case, we don’t need access to theunderlying data. So we could just go back to a value receiver. And then this is goingto work just fine. This is actually the initial example we had. If we have one method that’sgoing to appoint a receiver, however, we’re going to need to switch that over to a pointertype. And notice I can actually remove this.And it continues to work. Or I can make bothof these pointer receivers. And this continues to work as well. So this is an important conceptwhen you’re implementing your own interfaces. If any of the methods require a pointer receiver,you’re going to have to implement that interface with a pointer. If not, though, if all ofthe methods except value types, then you can go ahead and use a value type if that’s whatyou want. But you could also use a pointer. Okay, the last thing that I want to talk aboutare some best practices when using interfaces in your own go applications.So let’s takea look at those. Okay, when we’re working with interfaces, there’s a couple of rulesand guidelines that I’d like you to keep in mind. And these have been developed over thelast few years by the NGO community, and are generally accepted as some of the best waysto use interfaces, if it’s practical in your applications. The first is prefer many smallinterfaces versus large monolithic ones. Now, if you need large, monolithic ones, that’sfine, go ahead and compose smaller interfaces together to make those but the smaller youcan make your interfaces, the more useful and powerful they’re going to be. And that’snot actually unique to go. No matter what language you’re working in interfaces there.They’re generally having many smaller interfaces is preferable in the long run to having afew monolithic ones. Now, some examples that are in the go standard library are the IOdot writer interface, the IO dot reader interface in the empty interface.Now these are arguablythree of the most powerful interfaces in the entire language. And if you think about it,writer has one method reader has one method and the empty interface has zero methods.So it’s interesting support to the argument that smaller interfaces are better that someof the most powerful interfaces in the language contain one or zero methods on them. Now whenyou’re working with interfaces, if you’re coming from a language that has explicitlyimplemented interfaces, You’re going to be very tempted to create interfaces and exportthose. So here’s the guidance for that if you don’t need to export the interface yourself,so if you don’t have any particular reason to do it, go ahead and don’t.So there aresome good examples of why you would want to do that. But often, it’s perfectly acceptableto export the concrete type. I’ll take as an example, the database slashSQL package that we looked at earlier in the video, where we saw that the DB object wasexported as a concrete struct. And it had all sorts of methods that pointed to otherconcrete structs. So you can’t directly mock that out for testing right out of the box.However, by not exporting an interface, it allows you as the consumer of that structto define your own interface that you can use for testing. And the beauty of that is,if you don’t use every method on the DB object, your interface doesn’t have to have everymethod on it, you can just expose the methods that you need, however, do export interfacesfor types that you will be using.So if you’re going to pull a value in, go ahead and acceptan interface instead of a concrete type, if at all possible. So this is going to be almostexactly backwards from how other languages consider interfaces. And the reason is thatwhole idea about implicitly implementing interfaces instead of explicitly doing it. So if youwere working in Java or C sharp, you could not do this, because you have to define theinterface before you implement the interface, because they’re explicitly implemented. Butsince go has implicit implementation, you can go ahead and defer the creation of theinterfaces until exactly when you need them. So if you’re creating a library that otherpeople are going to consume, you can define the interfaces that you accept. And then theycan provide whatever implementations that they want. Now, if your library has reasonabledefaults, then you could export those concrete types as well. But make sure that you’re acceptinginterfaces whenever possible. And that’s what this third point is talking about.Designyour functions and methods to receive interfaces whenever possible. Now, that’s not alwayspossible. If you need access to the underlying data fields, then certainly taking the concretetypes. But if you’re accepting behavior providers, then go ahead and try and accept those asinterface types instead of the concrete types. Okay, so that covers what I want to talk aboutwith interfaces. today. Let’s go into a summary and review what we’ve talked about. In thisvideo, we’ve talked about interfaces and how to use them in the go language, we startedwith a discussion of the basics of interfaces, so how to create them and how to implementthem. And we ended up with code that looks something like this. So we’re defining aninterface as a type. So we’re going to start with the type keyword, the name of the interface,and then the keyword interface. And then inside of curly braces, things are going to be alittle bit different than if we were defining a struct. For example, if we were defininga struct, we would put data fields inside of the curly braces, because we’re definingthe data that that structure is holding.With interfaces. we’re defining behaviors, however,so instead of adding data fields, we’re gonna add method signatures. So we see here on thisexample, we’re going to define a write method that accepts a slice of bytes, and returnsan integer and an error. And then we implement that interface by creating a method on ourtype that has the same signature. So we don’t have to explicitly state that we’re implementingthe interface, we implement the interface by implementing the interface by having themethods there that match the type signature for the interfaces methods, then we talkedabout how to compose interfaces together, and how this is a preferable approach versuscreating a single monolithic interface, if you can break that interface down into smallertypes, and then compose them together.And we did that something like this. So we’regoing to create multiple interfaces. So we have a writer interface and a closer interface.And then when we compose them together, just like when we compose structs, by embedding,we can embed interfaces into one another. So we can create a writer closer interfacethat embeds the writer interface and the closer interface. So to implement that writer closerinterface, you have to implement the right method, because it’s defined by the writerinterface. And you have to implement the closed method as as defined by the closer interface.So by doing this, you can actually pass smaller chunks of your interface around your application.So for example, if a method only needs a writer, it doesn’t need a closer, then you can actuallypass this writer closer as a writer, and it worked just fine versus passing the entirewriter closer along, and potentially exposing methods to the consumer that aren’t reallynecessary.Then we talked about type conversion and how we can drill through the interfaceto get at the underlying types in case we need to work with those directly. So we hadan example here, where we created a writer closure instance, and the underlying typewas a pointer to a buffered writer closer, and how we could cast that back to a pointerto a buffered writer closer by using this syntax here, where we have a dot after theobject and then inside of print, we put the type We want to cast to know, we learned that when we did this, if the type assertionfailed, then we’re actually going to panic or application.So remember to use that comma,okay syntax, if you want to get a boolean variable out that you can run tests againstto see if that type conversion succeeded. And then we talked about the empty interfaceand type switches. The empty interface is nothing magic, it’s just an interface to findon the fly that has no methods on it. Now, it’s special in that every type in go implementsthe empty interface.So you can store anything you want in a variable of type empty interface.And then very often, we’re going to pair that with what’s called a type switch. And we seean example of that here, where we’re going to use the switch keyword, we’re going tohave the object and then dot and params, like we do with a type assertion. But instead ofhaving a concrete type that we’re asserting against, we put the keyword type in there.And then in our case statements, we’re actually going to put in the data type that we’re assertingagainst. So in this case, we’re looking for integers or strings, or we have a defaultcase, in case the value stored in i is neither an integer nor a string. After that, we talkedabout implementing with values versus pointers. And we learned about a concept called methodsets.Now, when you’re working with types directly, you never have to think about thisbecause the methods are always all of the methods assigned to that type. But with interfaces,the rules change a little bit. The method set of a value is all of the methods withvalue receivers. So if you’re going to try and implement an interface with a value type,than all of the methods that implement that interface, have to have value receivers.Withpointers, things are a little bit more flexible, because pointers always have access to theunderlying tape as well. The method sets for a pointer is all of the methods regardlessof the receiver type, so all of the value receivers, as well as all of the pointer receivers.So pointer types are definitely more flexible when you’re implementing interfaces. Justkeep in mind, you don’t want to assign pointer receivers everywhere without thinking aboutthe idea that that gives access to the underlying data of that type.And so that can allow methodsto alter that underlying data, even if you don’t want them to. So be careful when youmake that choice about using pointer receivers or value receivers. The last thing that wetalked about were some best practices that have evolved over the last few years aboutusing interfaces in the go language. And we talked about use many smaller interfaces wheneverpossible. And then if you need larger interfaces, go ahead and compose those together with interfacecomposition. Don’t export interfaces for types that will be consumed. So if you’re creatinga library, and somebody else is going to be consuming a type, go ahead and publish thatconcrete type out there don’t create an interface, assuming you know how people are going touse it, allow them to create the interfaces that your type will implement. That way, theydon’t have to implement a whole bunch of methods in their test suite that they never even use.Do export interfaces for types that you will be consuming however.So again, these twopoints are exactly opposite of how you’re going to think about interfaces, if you’recoming from another language, such as C sharp or Java, that have explicit implementationof interfaces. So when you’re defining a type that you’re going to be consuming in yourpackage, then go ahead and export interfaces. That way whoever’s using your package cancreate their own concrete types, and implement the interfaces that you need. So you don’tneed to worry about the implementation, you just need to worry about the behaviors thatthey’re exposing to you. And then, if possible, define your functions and methods to receiveinterfaces. Don’t get too crazy with this. So don’t go over the top. Use common sensewith this. But if you have the option of receiving interfaces, for example, if you don’t needaccess to the underlying data, then go ahead and define an interface that you’re goingto be receiving.That way it makes your methods and functions more flexible. Since you canhave multiple implementations that you never thought about at design time. And your functionsand methods will continue to work. Even when those new concepts are thrown at your application,I want to have a conversation about the tools that we have available to implement concurrentand parallel programming in the go language. Now, if you come this far in the series, or you’vedone any research and go at all, concurrent programming is one of the hottest topics thatis talked about, especially among people who are learning to go language for the firsttime. So we’re going to talk about this concept of a go routine, and how that enables us tocreate efficient and highly concurrent applications. We’ll start our conversation by learning howto create go routines themselves. So this is going to be the basics of how we creatego routines and how we can work with them a little bit. Then we’ll move into a conversationabout synchronization. And we’ll talk about two concepts, weight groups and mutexes. Andhow we can use those to get multiple go routines to work together.Because one of the challengesthat we’re going to have with go routines is also one of the greatest advantages. Goroutines are going to allow our application to work on multiple things at the same time.However, you’re often going to run into situations where you need a certain bit of functionalityin your application to weight into one or more of those concurrent calculations is complete.So we’ll talk about how to use synchronization primitives in order to do that. Then we’llmove into a discussion of parallelism. Now up to this point, our conversation is goingto be about concurrency in the go language. And concurrency is just the ability of theapplication to work on multiple things at the same time, it doesn’t mean it can workon them at the same time, it just means it has multiple things that it can be doing.When we talk about parallelism, we’ll talk about how we can take our NGO applicationsand enable them to work on those concurrent calculations in parallel, or in other words,introduce parallelism into our applications. And finally, we’re gonna wrap this video upagain, with a little section on best practices, just to talk about some of the gotchas thatyou can run into with concurrent and parallel programming, and some of the tools that areavailable to help keep your application safe and away from those minefields.Okay, so let’sget started by talking about how to create go routines. Okay, so the first thing thatyou’re going to notice is that we’re in Visual Studio code right now. Now, the reason forthat is while we can certainly play with go routines in the playground, when we startto get into parallelism, that’s going to be limited by the playground, because the playgroundonly enables us to use one core at a time. So when we’re running locally, we can useas many cores as we want. So we can truly run our applications in parallel. So someof the things that I want to show you are going to be easier to illustrate in this environment.So the first thing that I want to show you is how we can create our very first go routine.So the first thing that we’re going to need to do is we’re going to need to have a functionhere. So I will create a function called Say hello. And this is going to be a very simplefunction, all it’s going to do is well say hello.So we’ll start with that. And that’sgoing to be just enough for us to get started seeing what’s going to happen with our application.So we can of course, call the say hello function and call that from the main function. So wecan run this application by just using go run and pointing it to that file. And of course,it says hello, so no big surprises there. Now, to turn this into a go routine, all wehave to do is in front of the function invocation, just type the keyword go. Now what that’sgoing to do is that’s going to tell go to spin off what’s called a green thread, andrun the say hello function in that green thread.Now I need to take a little bit of a momenthere to talk about threads. most programming languages that you’ve probably heard of andworked with us, oh s threads are used operating system threads. And what that means is thatthey’ve got an individual function call stack dedicated to the execution of whatever codeis handed to that thread. Now, traditionally, these tend to be very, very large. They have,for example, about one megabyte of RAM, they take quite a bit of time for the applicationto set up. And so you want to be very conservative about how you use your threads. And that’swhere you get into concepts of thread pooling and things like that, because the creationand destruction of threads is very expensive. And so we want to avoid that in most programminglanguages, such as Java, or C sharp. Now, in go, it follows a little bit of a differentmodel. And as a matter of fact, the first place I saw this model was used by the Erlanglanguage. And this is using what’s called Green threads.So instead of creating thesevery massive heavy overhead threads, we’re going to create an abstraction of a threadthat we’re going to call a go routine. Now, inside of the go runtime, we’ve got a schedulerthat’s going to map these go routines onto these operating system threads for periodsof time, and the scheduler will then take turns with every CPU thread that’s availableand assign the different go routines, a certain amount of processing time on those threads.But we don’t have to interact with those low level threads directly. we’re interactingwith these high level go routines. Now the advantage of that is since we have this abstractiongo routines can start with very, very small stack spaces, because they can be reallocatedvery, very quickly. And so they’re very cheap to create and to destroy. So it’s not uncommonin a go application to see 1000s or 10s of 1000s of go routines running at the same time.And the application is no problem with that at all.Now, if you compare that to other languagesthat rely on operating system threads that have one megabyte of overhead, there’s noway you’re going to run 10,000 threads in an environment like that. So by using go routines,we get this nice lightweight abstraction over a thread, and we no longer have to be afraidof creating and destroying them. So anyway, let’s go ahead and run this and see what happens.And it’s going to be a little disappointing because you notice that our message doesn’tprint out. And the reason for that is our main function is actually executing in a goroutine itself. So what we did here in line six was we told the main function to spawnanother go routine, but the application exits as soon as the main function is done. So assoon as it spawn that go routine, it finished, it didn’t have any more work to do.So thesay hello function never actually had any time available to it to print out its message.So we can get around that a little bit by using a horrible practice, but it’s good enoughto get us started in understanding this. So we’ll just put an arbitrary sleep callinghere in order to get the main function to delay a little bit Now when we run the application,we see that we do get our Hello message printed out. Now, as opposed to our first run of this,it’s not actually the main function that’s executing this code. It’s a go routine thatwe’re spawning off from the main function. And that’s what’s responsible for printingout the message. Okay, now, this is a pretty typical use case of go routine where we’reusing the go routine to invoke a function.But we don’t have to do that. As a matterof fact, let me just drop in this example here, which is basically the same, exceptfor instead of using a named function, I’m using this anonymous function here. So noticethat I’ve got this anonymously declared function, and I’m invoking it immediately. And I’m launchingit with go routine. Now, what’s interesting about it is I’m printing out the message variablethat I’ve defined up here on line nine, down here inside of the go routine. So if I runthis, we do in fact, see that it works. Now the reason that it works is go has the conceptof closures, which means that this anonymous function actually does have access to thevariables in the outer scope. So it can take advantage of this MSG variable that we declaredup here on line nine, and use it inside of the go routine.Even though the go routineis running with a completely different execution stack. The go runtime understands where toget that MSG variable, and it takes care of it for us. Now, the problem with this is thatwe’ve actually created a dependency between the variable in the main function and thevariable in the go routine. So to illustrate how that can be a problem. Let me modify theexample just a little bit. So I’m declaring the variable message and setting it equalto Hello, and then printing it out in the go routine. And then right after I launchedthe go routine, right here on line 13, I’m reassigning the variable to goodbye. So ifI go ahead and run this, you’ll see that we in fact, get goodbye printed out in the goroutine, not Hello, like you might expect based on how the program is written. And thereason for that. And it’s not always going to be guaranteed to execute this way. Butmost of the time, the ghost scheduler is not going to interrupt the main thread until ithits this sleep call on line 14.Which means even though it launches another go routineon line 10, it doesn’t actually give it any love yet, it’s still executing themain function. And so it actually gets to line 13 and reassigns, the value of the messagevariable before the go routine has a chance to print it out. And this is actually creatingwhat’s called a race condition. And we’ll come back and talk about race conditions atthe end of this video. But this is a bad thing. And generally, it’s something that you wantto avoid, so that you can access variables via the closure, it’s generally not a goodidea to do that. So if that’s not a good idea, what are your other options? Well, noticethat we have a function here.And this is just a function invocation, there’s nothingspecial about it, just because we put the go keyword in front of it, it’s just a function.So functions can take arguments. So what happens if we add a message argument here, and thendown in the prints, where we’re actually invoking the function? What if we pass in the messageparameter? Well, since we’re passing this in by value, so we’re actually going to copythe string hello into the function, then we’ve actually decoupled the message variable inthe main function from the go routine, because now, this message that’s going to print outis actually a copy that we’re passing in when we’re invoking the function for the go routine.So now if we run this, we see that we get Hello printed out. So this is generally theway that you’re going to want to pass data into your go routines, use arguments to dothat, and really intend for the variables to be coupled together.Now, this exampleso far is working. But it’s really not best practice. And the reason it’s not best practiceis because we’re using this sleep call. So we’re actually binding the applications performanceand the applications clock cycles to the real world clock. And that’s very unreliable. Soin order to get your applications to work, you’re typically going to have to sleep fora very long time relative to the average performance time in order to get the performance to bereliable.So we don’t want to use sleep calls in production, at least not for somethinglike this. So what are the other alternatives? Well, one of the other alternatives that wehave is to use what’s called a weight group. So let’s go ahead and add one in. And thenwhile we’re doing that, we’ll talk about what they are. So I’m going to create another variable.And it looks like my auto formatting just helped me here. And we’ll pull that from thesync package. And we’ll create an object of type weight group. So I just need to put mycurly braces here to initialize it. Now what a weight group does is it’s designed to synchronizemultiple go routines together. So in this application, we’ve got two go routines thatwe care about, we’ve got the go routine that’s executing the main function. And we’ve gotthis go routine that we’re spawning off here on line 13. So what we want to do is we wantto synchronize the main function to this anonymous go routine. So we’re going to do that by tellingthe weight group that we’ve got another go routine that we wanted to synchronize to itstarts off synchronizing to zero.And so we’re going to add one because we want to tell itthat we’re going to synchronize to this go Right here. Now once it’s done, we don’t needthis line anymore. Once it’s done, we’re going to go ahead and exit the application. Andwe will do that by just waiting on the weight group. And we do that by using the weightmethod right here. Now when the go routine is done, then it can tell the weight groupthat it’s actually completed its execution. And we do that by using the done method. Soif we execute that, basically, what that’s going to do is it’s going to decrement, thenumber of groups that the weight group is waiting on.And since we added one, and it’sgoing to decrement by one to be down to zero, and then the weight method will say, Okay,it’s time for us to go ahead and finish up our application run. So if I save this off,and I go ahead and run it, we see in fact that our application is performing as it didbefore. But now it’s taking just enough time to complete the execution. We’re not relyingon the rolling clock anymore, and having to Jimmy run with variables and hope that everythingstays consistent. Now, in this example, we’re just synchronizing to go routines together.But only one of the go routines is really doing any work. The main function in thisexample is just storing data, and spawning other go routines. But we can have multiplego routines that are working on the same data.And we might need to synchronize those together.And that can be a little bit tricky. So let me drop in this example here, and we’ll talkabout it. So I’m creating weight group again, up here on line eight. And then I’m initializinga counter variable. inside of my main function, I’m actually spawning 20 go routines, becauseinside of this for loop, each time I run through, I add two to the weight group to let it knowthere are two more go routines that are running.And then I spawn a say hello, and then I spawnan increment here. And then I just have a wait method call here on line 17, just tomake sure that the main function doesn’t exit out too early now and say hello, all I’m goingto do is I’m going to print out Hello, and I’m going to print out the counter value.And then in the increment function down here, I’m just going to increment the counter byone. Now after each one of those is done, I’m going to call the done method on the weightgroup. And everything should be just fine. Now notice that I’ve broken my own rule here,the weight group is actually being accessed globally in this application. And that makessense, because I actually do want to share this object, and the weight group is safe to use concurrently like this. It’sdesigned to be using this way.So let’s go ahead and run this application and see what’sgoing to happen. So our intuition says that we’re going to print say, Hello. So it shouldprint say hello, zero, because the counters value is zero right here. And then it’s goingto increment it. And then it’s going to say hello, again, it’s going to increment it.So should say hello, number zero, hello, number one, hello, number two, and so on. So let’sgo ahead and run this and see what happens. And we see that we get a mess, we in fact,don’t have any kind of reliable behavior going on here, we printed one twice, and then 2345.So that seemed to work consistently. And then we jumped all the way to nine, we printed10 out twice, and then we went back to nine for some reason. And if we run this again,we’ll get a completely different result. So what’s happening here is our go routines areactually racing against each other. So we have no synchronization between the go routines,they’re just going hell bent for leather, and going as fast as they can to accomplishthe work that we’ve asked them to do, regardless of what else is going on in the application.So in order to correct this, we need to find a way to synchronize these guys together.Now, we could probably find a way to use a weight group on this.But we’ve already talkedabout weight groups. So I want to talk about another way to do this. So we’re going tointroduce this concept of a mutex. So with a mutex. let me paste this example in here,and then we’ll talk about what it does. But a mutex is basically a lock that the applicationis going to honor.Now in this case, you see on line 11, I’mcreating what’s called an rW mutex, which is a read write mutex. Now a simple mutexis simply locked or unlocked. So if the mutex is locked, and something tries to manipulatethat value, it has to wait until the mutex is unlocked. And they can obtain the mutexlock itself. So what we can do with that is we can actually protect parts of our codeso that only one entity can be manipulating that code at a time.And typically what we’regoing to use that for is to protect data to ensure that only one thing can access thedata at a single time. With an rW mutex, we’ve changed things a little bit. We’ve basicallysaid as many things as want to can read this data, but only one can write it at a time.And if anything is reading, then we can’t write to it at all. So we can have an infinitenumber of readers, but only one writer. And so when something comes in and makes a writerequest, it’s going to wait till all the readers are done. And then the writer is going tolock the mutex. So nothing can read it or write it until the writer is done. So in thismodification, actually, I don’t want to talk about that line yet.We’ll come back and revisitthat. So in this modification, what I’ve done here is I’m attempting to use a mutex to synchronizethings together. So the modification is down here in my say, Hello, I’m just reading thevalue of the counter variable. And that’s what I’m trying to protect. I’m trying toprotect the counter variable from concurrent reading and writing because that’s what wasgetting us into trouble. So on line 22, I obtained a read lock on the mutex and thenI print out my message and And then I released that lock using the R unlock method.Now inthe increment, that’s where I’m actually mutating the data. So I need to write lock. And soI’m going to call the lock method on the mutex, increment the value. And then I’m going tocall unlock. Now, if I run this application, I actually haven’t gotten quite where I wantto be. So I don’t get the weird random behavior that I was seeing before. But you notice thatsomething seems to be out of sync still, because I get Hello, one, hello, two, and then itstays at two. And if I keep running, this actually can get different behaviors. Butnotice that I’m always going in the proper order. So I fixed part of my problem, butI haven’t fixed all of it yet.So I can keep running. Actually, that one got pretty close.But there’s obviously something else going on here. With the reason that we have an issuehere is we’re still working within the go routines. So if this say hello, function getsexecuted twice by its go routines, and the increment function doesn’t get called in between.That’s where we get this behavior here, where we actually get the same message printingout twice, because we don’t have a chance to lock this mutex before we try and readit that second time. So the way to address this is we actually have to lock the mutexoutside of the context of the go routine. So we have a reliable execution model. Solet’s go ahead and paste in a small modification here. Now all I’ve done is I’ve moved thelocks out here.So the locks are now executing before each go routine executes. And thenI unlock them when the go routine is done. So if I run this, we actually see that I nowget the behavior that I expect, I see zero through nine printed out. And if I run itagain, and I run it again, and run it again, everything is working great. So the reasonthat this is working is I’m actually locking the mutex is in a single context.So the mainfunction is actually executing the locks. And then asynchronously, I’ll unlock themonce I’m done with the asynchronous operation. Now the problem with this application is Ibasically have completely destroyed concurrency and parallelism in this application. Becauseall of these mutexes are forcing the data to be synchronized and run in a single threadedway. So any potential benefits that I would get from the go routines are actually gone.As a matter of fact, this application probably performs worse than one without go routines,because I’m mucking around with this mutex. And I’m constantly locking it and unlockingit. So this is an example where if this is all that this application needed to do, wewould actually be much better served by removing the go routines, and just running this witha single execution path and removing any concurrency at all.However, there are often situationswhere you can get a significant advantage by running things in parallel. And so youcan use weight groups, or mutex is in order to synchronize things together, and make surethat your data is protected, and everything is playing well together. Now I have thisline in here, and I apologize for that I really shouldn’t have had that in these earlier examples.But I do want to talk about this function from the runtime package called go max procs.So in modern versions of go, if you look at this go max procs variable, let’s just goahead and execute this simple program, all it’s going to do is it’s going to tell me the numberof threads that are available. So it prints out that there are four threads availablein the application ends. Matter of fact, let me just add this carriage return in here andrun this again, that way things look a little better.And you see that I have four threadsavailable. So by default, what go is going to do is it’s going to give you the numberof operating system threads equal to the number of cores that are available on the machine.So in this virtual machine, I’ve exposed four cores to the VM. So I have by default four oh s threads thatI can work with. Now, I can change that value to anything I want. So for example, I canchange that to one. And now my application is running single threaded. So now I havea truly concurrent application with no parallelism at all. So this can be useful in situationswhere there’s a lot of data synchronization going on. And you really need to be carefulto avoid any kind of race conditions that parallelism can incur. And maybe there’s nobetter way to do it. Now, I would say there’s an architecture problem there. But it is possibleto run an application in a single threaded way, by setting go max procs equal to one.Now if you’re wondering what this negative one does, when you invoke the go max procsfunction, it actually returns the number of threads that were previously set.And if youpass a negative number, then it doesn’t change the values. So this go max procs, negativeone, all that’s doing is that’s letting us interrogate how many threads we have available.Now we can also set this to for example, 100. There’s nothing stopping us from creatinga massive number of operating system threads. Now what I found in working with NGO is thatgo max procs is a tuning variable for you to work with. So the general advice is oneoperating system thread per core is a minimum. But a lot of times you’ll actually find thatyour application will get faster by increasing go max procs beyond that value. Now if youget up too high Like, for example, 100, then you can run into other problems, because nowyou’ve got additional memory overhead. Because you’re maintaining 100 operating system threads,your scheduler has to work harder because it’s got all these different threads to manage.And so eventually, the performance peaks and it starts to fall back off, because your applicationis constantly rescheduling go routines on different threads.And so you’re losing timeevery time that occurs. So as you get your application closer to production, I wouldencourage you definitely develop with go max procs greater than one because you want toreveal those race conditions as early as possible. But just before you release to production,you might want to run your application through a performance test suite with varying valuesof go max procs, to see where it’s going to perform the best.Now, the last thing thatI want to talk about are some best practices to keep in mind when you’re working with goroutines in the go language. So let’s take a look at those next. Go routines in the golanguage are very powerful, and it can be easy to let them get a little bit out of hand.So I want to go through and give you some advice on how to work with go routines inyour own applications. The first bit of advice is, if you’re working in a library, be very,very careful about creating go routines yourself, because generally, it’s better to let theconsumer control the concurrency of the library, not the library itself. If you force yourlibrary to work concurrently, then that can actually cause your consumers to have moreproblems synchronizing data together. So in general, keep things simple, keep things singlethreaded, and let the consumer of your library decide when to use a go routine and when notto now, this advice can be softened a little bit, if you have a function called that’sgoing to return a channel that will return the result, then having the go routine inthere might not be such a bad thing, because your consumer never really has to worry abouthow that unit of work is getting done.They don’t really care if it’s running concurrentlyor not. Because they are just going to be listening for the result on a channel. Butwe haven’t talked about channels yet. So we’ll revisit that topic in the next video. Butfor now, if you’re creating a library, trying to avoid go routines, at least go routinesthat are going to be surface to the consumer and have them forced to work with them. Whenyou create a go routine, know how it’s going to end. Now we’re gonna see how to do thisa little bit more when we talk about channels. But it’s really easy to have a go routinelaunched as kind of a watch or go routine. So it’s going to be just sitting out therelistening for messages to come in.And it’s going to process those messages as they arrive.However, if you don’t have a way to stop that go routine, that go routine is going to continueon for ever. And so it’s constantly going to be a drain on the resources of your application.And eventually, as the go routine ages, it could even cause other issues and cause yourapplication to crash. The other thing that I want to give you some advice about is checkfor race conditions at compile time. So I want to jump back over to the editor and showyou how to do that. But it’s very important and very simple to do in most environmentsthat go runs in. So let’s jump over to the editor and take a look at that in order tosee if we don’t have to go any further than this example.Now I know this is right fromthe beginning of the video, and it’s got sleeps in there. And it’s got some bad practices.But if you remember, if we run this application, then it prints goodbye instead of the Hellomessage that we originally printed. So how could we have detected this without runningthe application? Well, you might not think it’s terribly important to be able to do that.Because it’s obvious, we’ve got some kind of a problem here. And all we have to do isapply our debugging skills. But there are other cases where this is very, very subtleand very, very hard to track down without a little bit of help. Well, fortunately, thego compiler has quite a bit of help available to you.And it’s as simple to invoke as justadding a dash race flag to go run, go install, go build whatever you’re using to get yourapplication up and running. So let’s go ahead and try that and see what it says about ourlittle application here. And you notice it does run the application because we invokedgo run so we see goodbye printed here. But notice what we got up here we got this datarace message. So it’s telling us it sees that the same area of data is being accessed bytwo different executing go routines. So it says the first one that it found was in goroutine six which an internal identifier unless we’re profiling, we’ve got no idea what goroutinesix is, but it does tell us it was invoked on line 11.So apparently in this run, goroutine six was this go routine right here. And it was accessing the MSG variable. Italso sees that we access the MSG variable on line 13, which is in our main function.And so by adding the dash race flag, we get all of this additional information where thego compiler itself, analyzes our application and tries to determine if we have any raceconditions. So I would strongly encourage you if you get any kind of concurrency atall in your application, you’re going to want to run this because it’s very simple checkit runs very, very quickly. And it’s going to help you prevent very subtle bugs fromgetting into your production code. Okay, so that’s what I have to talk about.With go routines, maybe you are expecting more. But go routines are really quite simple.Now when we get into our next conversation, which will be about channels, things get alittle bit more complicated, but go routines are relatively straightforward.So let’s gointo a summary and review what we’ve talked about in this video. In this video, we learnedabout go routines and how we can use them to create concurrent and parallel executionpaths in our applications. We started by learning how to create go routines themselves. Andwe learned that by adding the go keyword in front of a function call, we’ve created ago routine. And that’s all that it takes. There’s no special semantics, there’s no specialthings that need to be done. It’s simply a function call with the keyword go in frontof it. Now when we’re using anonymous functions, we in general want to pass data as local variables.So you want to add a parameter into that anonymous function and pass data into the go routine,instead of relying on the closures to prevent any kind of race conditions as you try andmanipulate that data.And that’s not always true. We saw with weight groups that we accessthat globally, because that was our intention, we truly did want that to be available inmultiple scopes. But even then we could pass a pointer in, in order to be very clear aboutwhat information that go routine should have access to. Then we talked about the differentways that we can synchronize multiple go routines together, one of the challenges that we havewith go routines is now we’ve got all sorts of things happening. And there’s no way toensure without synchronization, how they’re going to interact with one another. Now fora lot of concurrent calculations, that’s not a problem at all, because the two might notbe related to one another. But often you get into situations where you’re relying on theresult of multiple calculations, or something needs to know the result of the work that’sbeen done, or you’ve got a shared memory issue.And you need to make sure that those go routinesaren’t trying to manipulate the same data at the same time. So we can use weight groupsto wait for groups of go routines to complete. So we saw that we have three methods thatare interesting. There, we have the Add method to inform the weight group that there aremore go routines for it to wait on, we have the weight method that’s going to block thego routine that is called on until the weight group is completed. And then we have the donemethod available on that weight group that lets the weight group know that one of thego routines is completed with its work.We also talked about the mutex and the rWmutex, and how those are generally used to protect data. So if you have a piece of datathat’s going to be accessed in multiple locations in your application, then you can protectthat access by using a mutex or an rW mutex. To ensure that only one go routine is manipulatingthat data at one time. We then talked about parallelism and how parallelism can introducesome really tricky challenges into your go applications. We talked about how by defaultgo will use the number of CPU threads equal to the number of available cores on the computerthat is running on. We talked about how we can change that by using the go max procsfunction from the runtime package. And we talked about how more threads will generallyincrease performance. But too many can actually slow it down. So in general, if you’re developingan application, you want to start from day one with go max procs greater than one tofind any concurrency and any race conditions early on in your application development.But don’t settle on a final number until right as you get close to production and you havea performance test suite that you can work with.To find out what the best value forgo max procs is for your application. Because while the starting number is a very good numberto start with, a lot of applications actually perform better with a value higher or lowerthan that default value. And finally, we wrapped up with a discussion of some best practicesto keep in mind when you’re working with go routines. We learned that if you’re a librarydeveloper, you should avoid the creation of go routines that are going to be exposed tothe consumer of your library.Let the consumer control the concurrency of your applicationbecause they’re the ones that are in the best place to know if something needs to be executedsingle threaded, or if it can be executed concurrently. When creating a go routine,know how it’s going to end. It’s very easy to get into situations where go routines startleaking memory because they’re never cleaned up because they never quite get done withtheir work. Now normally a go routine is killed as soon as it finishes its execution. Andwe saw that with the main function, the main function runs in a go routine. And that goroutine terminates as soon as the main function exits. We also saw in our say hello function,as soon as it printed its message out and the function exited. That go routine was killedand it was cleaned out. So it was very clear when those go routines life cycle is goingto be over. However, if you’ve got go routines that are listening for messages in a continuousloop, then make sure that you code in a way to shut those go routines down so that onceyou’re done using them and clean up the memory that they’re using.Also, as you’re goingalong with your application development, check for race conditions, it’s not that hard todo. You just have to add dash race onto the go command that’s compiling your application.And then the go compiler is going to analyze your application and try and locate placesin it that have the potential of access Seeing the same memory at the same time, or in anunsynchronized way, causing very subtle and potentially very disastrous bugs where yourapplication when it gets to production. Over the course of this video series, we’ve talkedabout a lot of structures and techniques and tools that are available. In order to getstarted successfully programming with the go language. Well, I want to wrap up thatdiscussion in this video by talking about one of the features that makes go really standout when you’re looking for different languages to work with.And that is this concept ofchannels. Now most programming languages that are out there, were originally designed witha single processing core in mind. And so when concurrency and parallelism came into play,they were really kind of bolted on to the side. And so a lot of times, you’re actuallygoing to be working with third party libraries and packages in order to help with data synchronizationand things like that. Well go was born in a multiprocessor world. So every computerthat was out there when go was invented, had more than one processing core. So it madesense as the language was being designed to consider concurrency and parallelism fromthe beginning. Now in the last video, we talked about go routines, and how go abstracts theconcept of a thread into this higher concept called a go routine to allow hundreds or 1000sor even 10s of 1000s of things to be going on in your application at the same time.Onthis video, we’re going to be talking about channels, and how those can be used to passdata between different go routines in a way that is safe, and prevents issues such asrace conditions, and memory sharing problems that can cause issues in your applicationthat are very difficult to debug. So we’re going to start this talk by talkingabout the basics of channels. So we’ll talk about how to create them, how we can use themhow we can pass data through them, then we’ll talk about how we can restrict data flow.Now a basic channel is a two way street, we can send data in and we can get data out.But that’s not always what you want to be able to do with the channel.Sometimes youwant to send only channel or receive only channel. And we’ll talk about how to do thatin the second section. Then we’ll talk about buffered channels, and how we can actuallydesign channels to have an internal data store so that they can store several messages atonce just in case the sender and the receiver aren’t processing data at the same rate. Thenwe’ll talk about how we can close channels once we’re done with them. We’ll then revisitthe topic of four range loops. And we’ll learn how we can use channels with a four rangeloop.And then we’ll wrap up our discussion by talking about SELECT statements, whichis kind of like a switch statement, but specifically designed to work in the context of a channel.Okay, so let’s go ahead and dive in and learn the basics of working with channels. So when we’re working with channels in thego language, we’re almost always going to be working with them in the context of goroutines. And the reason is because channels are really designed to synchronize data transmissionbetween multiple go routines. So let’s go ahead and get started by creating some goroutines. Well, actually, the first thing that I need to do is I need to create a weightgroup. Because as you remember from the last video, we use weight groups in order to synchronizego routines together. So we’re going to use the weight group to synchronize the go routinesto make sure that our main routine waits for all of our other go routines to finish. Andthen we’re going to use channels in order to synchronize the data flow between them.So we got two different synchronization mechanisms going on in this little application.The nextthing we need to do is we need to create a channel. Now channels are created with thebuilt in make function. And there really is no shortcut around this. Now a lot of usesof the make function, you can actually use other forms. When you’re creating a channel,there’s enough internal mechanisms that need to fire that you have to use the make functionin order to allow the runtime to properly set up the channel for you.Now on the simplestform of the make function with working with channels, we’re going to use the channel keywordto say that we want to create a channel. And then we’re going to provide the data typethat’s going to flow through the channel. Now you can pick any data type that you want,we’re just going to be using integers here. But keep in mind that this means that thechannel is strongly typed, you can only send integers through this channel that we’re creatinghere. Similarly, if we provided strings, we could only pass in strings.If you providedpointers to integers, you can only send in pointers to integer, you get the general idea.So when you create a channel, you’re going to create that channel to accept messagesof a certain type. And it’s only ever going to receive them send messages of that type.Now in this initial example, we’re going to have to go routines, I’m going to spawn soI’m going to add two items to my wait group. And then we’ll go ahead and create those goroutines, and then we’ll talk about those. So let me just drop in the rest of the codehere. And you can see my first go routine is an anonymous function actually both ofthe marm and this first one is going to be receiving data from the channel. So this goroutine is actually going to be my receiving go routine. And then this channel is actuallygoing to be my sending go routine. So the way that we send a message into a channelis as you see here, we’re going to use this arrow syntax, so we’re going to use a lessthan and a dash, and when we’re putting data into the channel we list the channel first,then we have this arrow and then the data that we want to pass in.So imagine that thearrow is pointing in the direction that we want the data to flow. So we want the datato flow into the channel, and so the arrow is pointing toward the channel. Similarly,if we want to receive data from the channel, then we’re going to put the arrow on the otherside. So we’re going to use that same less than and dash, but it’s going to be beforethe channel. And so we’re going to be pulling data from the channel. So in this line righthere, on line 14, we’re going to be receiving data from the channel and assigning it tothe variable i. And then after we’re done, we’re going to call the done method on ourweight groups. And we’re just going to print the value out. So all we’re doing here isthis go routine is going to be sending the value 42, this go routine is going to be receivingwhatever value comes out of the channel, which in this case, of course, will be 42.And it’sgoing to print that out to the console. So let’s go ahead and run that. And we see thatin fact, it does work. So the nice thing about doing this is since we’re sending a copy ofthe data to the channel, we could manipulate the variable assigned here. So for example,we could actually start this off with I set equal to 42. And we can pass in I and thenafterwards, we can reassign I, and it doesn’t matter because like with all other variableoperations and go, when we’re passing data into the channel, we’re actually going topass a copy of the data. So when we manipulate it afterwards, the receiving go routine doesn’treally care that we change the value of the variable, it’s not affected by that at all.Now another common use case for go routines is if you have data that’s asynchronouslyprocessed, so maybe you can generate the data very, very quickly, but it takes time to processit.Or maybe it takes a long time to generate that data. So you’ve got multiple generators,but it can be processed very quickly. So you might want to have a different number of goroutines that are sending data into a channel, then you have receiving. So let’s take a lookat how we can do that. So it’s a slight modification to the example that we just went through,instead of just having the go routines fire once, I’m actually creating go routines insideof this loop here.So I’m going to create five sets of go routines. So each one of thegroups is going to have a sender like we have here, which is exactly what we had before.And then we’re going to have a receiver, which is again, just like we had before. So by thetime the application is done, we’re going to spawn 10 go routines here, five sendersand five receivers, and all of them are going to be using this single channel to communicatetheir messages across. So if we go ahead and run this, we see that we do get five messagesreceived. Okay, so this works out really well, well,but I will warn you, if you start playing around with this, and you decide to startmoving the senders and receivers to make them asymmetrical, things won’t work very well.So one of the things you might want to do to play with this example is take this goroutine, and move it outside of the for loop.So you’re gonna have one receiver and multiplesenders at the end of this, well, that actually isn’t going to work right now. Because ifyou think about how this go routine is going to process, it’s going to receive the messagecoming in from the channel, it’s going to print and then it’s going to exit, but thendown here in the loop, we’re actually going to spawn five messages into that channel.So we can only receive one, but we’re sending five. And if we run this, we’re actually goingto run into a problem. And that is we see all routines are asleep, that we have a deadlockcondition.And the reason for that is because we have these go routines down here that aretrying to push messages into the channel. But there’s nothing that can process them.Now an important thing to keep in mind here is the reason that this is a deadlock. Andthe reason for that is this line of code here is actually going to pause the execution ofthis go routine right at this line until there’s a space available in the channel. So by default,we’re working with unbuffered channels, which means only one message can be in the channelat one time. So our first go routine in this loop gets happily spun up, it pushes a messageinto the channel, and then it exits and then calls this done method on the weight group.And then that message gets processed by this go routine here and everything’s happy.However,this go routine then exits. And then our next go routine comes along and tries to push anothermessage in. Well, it blocks right on this statement. And there’s nothing in our applicationthat’s going to receive that message. And that’s why we see the go runtime. Notice thatand it’s going to kill the application because it notices that we have a problem, and itdoesn’t know how to resolve it. Now I want to go back to our previous example. And actuallyI’m going to modify things slightly here. Because I want to show you that notice thatwe’re just working with the raw channel. So this is perfectly valid code for us to write.As a matter of fact, if I go ahead and run this, we see that we get two messages printedout but look at how that’s happening.So this go routine is pushing a message into the channel.That message is then being received up in this go routine and printed out this go routinethen the one that received this message is then putting a message back into the channel.And that is then being received down here and this go routine, which is then printingthe message out. So both of these go routines are actually as readers and writers, now thatmay be a situation that you want, but very often, you want to actually dedicate a goroutine to either reading from a channel or writing to a channel. So in order to do that,what we’re going to do is we’re actually going to pass in the channel with a bias on thedirection that is going to be able to work with.So the way we’re going to do that isby accepting variables in our go routines. So we’ll start with this first one here. Andwe want this to be a receive only channel. So the way we’re going to do that is we wantdata to flow out of the channel. So you notice we’re using that similar syntax, we’re goingto list the type of the channel, and then we’re going to have this arrow coming outof it.So data is flowing out of the channel. And so this is going to be a receive onlychannel. Similarly, if we want a send only channel, we’re going to give it the variablename, we’re going to say that it’s a channel, now we put the Send only operator right here,and then we put the data type. So this is going to be sending data into the channelonly. And this is going to be receiving data from the channel. And then of course, we haveto pass the channel into the go routines as arguments. So when we run this, we’re actuallygoing to get an error. And the reason we get an error is because we’re trying to pass datainto this channel.But this is a receive only channel. So it’s invalid to send data intoit. And then similarly, we have an error down here on line 21, because we’re trying to receivedata from the Send only channel. So if we go ahead and wipe out these lines here, thisline, and this line, and run, then everything works as it did before. But now it’s muchmore clear what the data flow is in the go routine, we know that we’re going to be receivingdata on one side, and we’re going to be sending data on the other.Now something that’s alittle unusual with this is notice that we’re passing in a bi directional channel. So thisis just a normal channel, and we’re receiving it a little bit differently. So this kindof feels like a little bit of polymorphic behavior. And this is a special aspect ofchannels, the runtime understands this syntax. And so it actually is going to, I’m goingto use the word cast here, it’s going to cast this bi directional channel into a unidirectionalchannel. But that’s not something you can generally do in the go language. That is somethingthat is specific to channels. Now one of the problems we ran into on a previous exampleis we had a situation where we tried to push five messages into a channel, but we onlyhad one receiver. And we noticed that the application deadlock, well, we can get aroundthat in a couple of different ways. Now I’m going to show you one way to get around thatthat really is nice deal for solving that problem. But I will talk about the problemthat it is solving.And that is by using buffered channels. So if I go ahead and paste in thisexample, here, we will see an example of the problem we might run into. I’ve simplifiedit a little bit from the previous example we ran into. So we’ve got our initial examplewhere we’ve got a receive only go routine, we’ve got a send only go routine. But in oursend go routine, we’re actually sending two messages. But since we’re only receiving one,we expect that we’re going to run into a problem. So let’s go ahead and run this. And we seethat we do in fact have a problem, we received the 42 out and printed it. But there’s nothingto deal with this message here that’s in the channel. And so the application blows up,because this go routine can never complete, because it’s blocked on this line. So we needa way to get around that. Now a simple way to get around that is by simply adding a bufferhere. So if we add a second parameter to the make function up here, and provide an integer,that’s actually going to tell go to create a channel that’s got an internal data storethat can store in this case, 50 integers.Now what that’s going to do is it’s actuallygoing to allow our application to complete. But we do have a little bit of a problem herebecause this message is lost. So it did eliminate the panic. And I guess in one way, you couldsay it solved the problem. But it did create another problem in that we lost this message.Now this isn’t the problem that buffer channels are really intended to solve. But I do wantto show you that it does create that internal store, so we can receive multiple messagesback out. As a matter of fact, what we can do is we can just copy this line down hereand reformat this, and we don’t need this column right here.And if we run this, wesee that we do get both messages printed back out. Now what a buffered channel is reallydesigned to do is if the sender or the receiver operate at a different frequency than theother side. So you can imagine if we had a data acquisition system, and maybe we retrievedata from our sensors, and a burst transmission, so maybe we’re acquiring data from seismometers,and we’re monitoring earthquakes, well, maybe those seismometers in order to conserve power,don’t send their data continuously, they’re going to send a burst transmission, maybeonce an hour. So every hour, we’re going to get a burst transmission that maybe last fiveor six seconds, that’s going to contain the entire hours worth of data.So in that case,our sender is going to be inundated with data when that burst happens. And it’s going tohave to have a way to deal with it, one of the receivers might take a little while toprocess that data. So in that case, what we might want to do is create a buffer here ofthese signals that are coming in from our seismometer, that’s going to be able to acceptthat one hours worth of data.And then our receivers can pull that data off, as they’reable to process it, and keep things working smoothly, so that the channel that’s receivingthe data from our sensors, doesn’t get locked up, because it doesn’t have a place to putthe next message. So that’s really what buffered go routines are designed to work with, iswhen your sender or your receiver needs a little bit more time to process. And so youdon’t want to block the other side, because you have a little bit of a delay there. Nowif this isn’t the right way to handle this situation, what is the right way? Well, theway that we typically handle something that’s going to happen multiple times, such as passinga message into a channel, is by using some kind of a looping construct.And that’s nodifferent with channels as is with anything else. So let’s paste in this example, whereI instead of processing the message once and then having this first go routine exit, I’mactually going to use a for range loop. But notice what I’m arranging over, instead of ranging over some kind of a collection,such as an array, a slice or a map, I’m actually ranging over the channel. Now the syntax changesjust a little bit. Because if this were a slice, the first index that we pull back isgoing to be the index in the slice. And then the second variable we pulled out, if we had,for example, a second variable here would be the value. Well, when you’re arrangingover a channel, things are a little bit different. When you pull a single value, you’re actuallygoing to get the value that’s coming out of the channel. And so if we run this, we seethat we do in fact get 42 and 27. But we still have a deadlock condition. So what’s causingthat deadlock condition? Well, before we had this four range loop, we actually deadlockedthis go routine right here, and everything died.We’re in our new application, we’reactually deadlocking in the four range loop. And the reason for that is because we’re continuingto monitor for additional messages, but we stopped sending messages. And so now thisfour range loop doesn’t know how to exit. And so this go routine is now causing thedeadlock condition. So we’ve improved the situation, we kind of move the needle wherewe’re no longer dead locking in our sender, but we are still dead locking in our receiver.So how do we handle that? Well, the way that we’re going to handle that is we have to understandhow the four range loop works. So if you’re using a for range, loop over a slice, howmany times does that iterate? Well, it executes the loop once for every item in the slice.So if you’ve got a slice with five elements in it, you’re going to run through the fourrange loop five times, well, how many elements are in a channel? Well, there can be an infinitenumber of elements in a channel because you can constantly push a new message into it.So what is the way to signal a four range loop with a channel that there are no moremessages coming? Well, the answer is we need to close the channel.So anything that hasaccess to the channel can do this, we’re going to use the built in close function. And we’regoing to pass in the channel like you see here. So what we’re doing on our sending sideis we’re passing in two messages, we’re passing in 42, and 27. And then we’re letting thechannel know we’re done working with you. So we’re going to go ahead and close the channel,this four range loop is going to detect that. And when we run this, now everything runswell, because we’re passing in the message 42, that gets processed in the for loop, we’repassing in 27, that gets processed, then we close the channel, that gets processed bythe for range loop, which notices that the channel is closed, and it’s going to exitand it’s going to terminate the loop. So when we terminate the loop, then we call the donemethod on the weight group.And then we exit the go routine, all of our go routines exitproperly, and we have no more deadlocks. Now we do have to be a little bit carefulin closing channels, because when you close a channel, you really have to mean that you’reclosing the channel down. So let’s try closing the channel right here and then pushing anothermessage into it. So if we run this, we actually get a bad thing happening. So in this case,the application panicked. And why did it panic, because we tried to send a message on a closedchannel. So the issue here is we close the channel right here on line 21. And then online 22, we tried to pass another message into it.So that is a no, no, you are notallowed to pass a message into a closed channel because the channel is closed. So you mightask, Well, how do I recover from this? How do I reopen the channel or undo that or whatever?And the answer is, you can’t. As a matter of fact, you can’t even detect if a channelis closed, except for by looking for the application panicking. So call that a limitation of thego language or not, I don’t know. But you do have to be very careful that when you closea channel, nothing else is going to send a message into it.So if that is a possibility,then the only option you really have is to have a deferred function and use a recoverin there to recover from the panic that gets thrown because in this situation, you willhave a panic and there is no way to avoid it. So if in your application, that’s a situationthat’s likely to happen, then again, you’re going to have to use that recover function.And you can review the video where I talked about using those. Now on the receiving side,we do have a little bit of a different story here, because this issue is on the closingside. So we cannot send the message into a closed channel. And we can’t detect if a channelis closed before we try and send a message into it. However, if we go on the receivingside, then the story gets a little bit brighter. So you might ask the question, how does thefour range loop know that the channel is closed, it has to have some way of detecting it, whatturns out that there’s more than one parameter that you can pull back from the channel.Sojust like when we’re querying maps, and we’re trying to get a value out of a map, and wecan use that comma, okay, syntax, well, that syntax works for channels as well. So if Ichange this example up a little bit, and this is going to do exactly the same thing as ourcurrent example, here using a four range loop, but instead of using the four range loop,and having go automatically processed the closed channel for us, we’re going to processthis manually. So let me paste in this example and show you so notice that I’m in a for loopin this go routine, and I don’t have any conditions on it.So this is going to execute forever.Down here, then I’m receiving a message from the channel, and I’m using the comma. Okay,syntax. So I’m going to get the value from the channel and I and I’m going to get a Booleanletting me know if the channels open or not in the okay variable. So if the channel isopen, then okay is going to be true. If the channel is closed, then Okay, it’s going tobe false. So the happy path, if okay is true, then I’m going to go ahead and print out mymessage.Otherwise, I’m going to break out of this for loop here, because the channelsclosed, and I’m not going to be receiving any more messages from it. So this is functionallyexactly the same as the four range construct. But we’re explicitly seeing this comma, okay,syntax. So which one would you use? Well, in this situation, it would make moresense to use the for range construct. But there may be situations where you’re receivingdata from a channel, and you’re not in a loop.So maybe you’re spinning off a new go routinefor every time you’re processing a message. And so the loop is going to contain the spinningoff of the go routines. And so you’re going to need this comma, okay syntax, because itmight not make sense to use the for range loop. Now, the last thing that I want to talkabout in this video are what are called SELECT statements. So let me go ahead and paste inthis code here. So we talked about in the last video, how there can be situations whereyou create go routines that don’t have an obvious way to close. And that’s what I wantto try and illustrate here. So if I go ahead and run this, we see that we do get thesemessages printed out. So I’m just doing a simple logger implementation. So what yousee here is I’ve got some constants that are declaring my log level, I’ve got a structthat I’ve declared the holding the timestamp for the login tree, the severity of the loglevel, and then whatever message I’m trying to print out, then I’m creating a log channel.And the way this application works, is the first thing the main function does is it spinsup this go routine, that’s going to be my logger.And what it’s going to do is it’ssimply going to monitor that log channel for log entries that are coming from throughoutmy application. So the idea is I’ve got a central logger, and anything that could dologging in, my application just needs to know about this channel. And all of my logginglogic can be hidden within the processing of those log channel messages. So the loggeris down here, we’ve got a four range loop that’s listening for messages from the logchannel. And all it’s doing is it’s printing out a formatted message that’s got the timestamp,it’s got the log level, and it’s got the message from the log. So no big deal here, nothingterribly exciting. Then my main function goes on to exercise that a little bit, it sendstwo messages into the log channel, one letting it know that the application is starting anotherone letting the application note shutting down. And then I’ve got a sleep call herejust to make sure that the logger co routine has enough time to process that.Now you noticemy timestamps are a little funny here. That’s because I’m working with the playground, Ipromise you this code does work. If you shifted over to Visual Studio code, you will actuallyget real timestamps. But for some reason, the playground doesn’t give you the currenttime when you call the now function. And so this is just something that we’re going tohave to work with in this example. Now the problem I want you to consider is when doesthe logger go routine closed down. So obviously, the logger go routine has to terminate sometimebecause the program finishes execution, and we get the results back from the playground.So what’s happening here is remember, an application is shut down as soon as the last statementof the main function finishes execution. So when we finish this sleep call here, the applicationterminates and everything is torn down and all resources are reclaimed as the go runtimereturns all of the resources that it was using back to the operating system. So what thatmeans is that our logger go routine is being torn down forcibly.There’s no graceful shutdownfor this go routine. It’s just being ripped out because the main function has done. Nowin some situations like this one that may be acceptable. But there are many situationswhere you want to have much more control over a go routine. Because remember what I saidin the go routine video, you should always have a strategy for how your go routine isgoing to shut down when you create your go routine. Otherwise, it can be a subtle resourceleak, and eventually, it can leak enough resources that it can bring your application down.Sothere’s a couple of different things we could do here, right, we could of course, do a defercall here, we can pass in an anonymous function. And inside of that, we could go ahead andclose the log channel. So what that’s going to do is when the main function exits, it’sgoing to go ahead and close the channel, and then we are gracefully shutting down thatchannel. And that works just fine. There’s no issues with that we are intentionally closingdown the channel, we know how our go routine is going to close. And so this is perfectlyacceptable in this use case. But this isn’t what I want to show you. So this is certainlysomething you could use in this use case. But I want to show you another way that verycommonly used in these kinds of situations.So the way that I want to show you is usingwhat’s called a select statement. So let me go ahead and paste in that code. And we’llwalk through that. So the application is basically the same, I’ve got the same constantshave here, I’ve got the same struct, I do have this additional channel here. And noticethe type signature for it. So it’s strongly typed, but it’s strongly typed to a structwith no fields. Now struct with no fields in the go language is unique in that it requireszero memory allocations. So a lot of times you will see a channel set up like this. Andthe intention is it can send any data through except for the fact that a message was sentor received. So this is what’s called a signal only channel. There’s zero memory allocationsrequired in sending the message. But we do have the ability to just let the receivingside know that a message was sent. So this is pretty common, you might be tempted ifyou’re new to the language, like I first did you send a Boolean in here.But that doesactually require a variable to be allocated and copied. So it is actually better to usean empty struct because it saves a couple of memory allocations. It’s a little bit minor.But it is something that if you are going to use a channel as a pure message, then youmight as well go with the conventions and use this approach. So our main function isexactly the same as it was before. We’ve got our logger, we’ve got our log channel, sendingin a couple of messages. And then we got a sleep call here. And then inside of our loggerfunction, we’ve got an infinite loop now, and we’re using this select block.So whatthis SELECT statement does is the entire statement is going to block until a message is receivedon one of the channels that it’s listening for. So in this case, we’ve got a case listeningfor messages from the log channel, and the case listening for messages from the donechannel. So if we get a message from the log channel, then we’re going to print out ourlog entry. If we get a message from the done channel, then we’re going to go ahead andbreak out of this for loop. So what this allows us to do is at the end of our application,we can go ahead and pass in a message into our dumb channel. And that is going to bean empty struct. And I’m just going to define that empty struct on the fly here. So thisis a little bit confusing syntax. But this is the type signature for my struct. So I’mdefining a struct with no fields. And then I’m initializing that struct using these curlybraces here.So if I go ahead and run this, you see that the application runs properly.So I do process my log messages. And then I pass in this message into my done channelwhen I wish the logger to shut down. So this is a common situation for you to use whenyou’re monitoring channels. And you need a way to have the go routine that’s monitoringthose handles be able to terminate. So very often you’re going to send in normally asa parameter, you’re going to send in this done channel. And then whatever’s ready tokill the go routine, will go ahead and send a message into that done channel. And it’llgo ahead and kill it. Now one more thing that I do want to talk about. And I’m not goingto actually run it because it’s going to break our application here.But you can have a defaultcase here. And if you do, then this no longer becomes a blocking SELECT statement. So whatthis is going to do is if there’s a message ready on one of the channels that are beingmonitored, then it’s going to execute that code path. If not, it will execute a defaultblock. So this is useful. If you want to have a non blocking SELECT statement, then youneed to have that default case in there. If you don’t have the default case, then theselect statement will block forever until a message does come in.Okay, so that’s whatI have to talk about with channels. Let’s go into a summary and review what we’ve talkedabout. In this video, we talked about channels and how we can use them to synchronize datatransmission between go routines. We started out by talking about the basics of workingwith channels. And we learned that we can make our channels using the built in makefunction and how that’s really the only way that we have available in the go routine tomake a channel. When we do make those channels, those channels are strongly typed. So we’regoing to use the chain keyword to indicate that we wish to create a channel and thenwe have to follow that with the data type that the channel is going to be Send and Receive.Now that data type can be anything, it can be a primitive like we see here with an integer,it can be a struct, it can be an interface. But it does have to be strongly typed, wecan send a message into the channel using this arrow syntax.And the position of thearrow kind of indicates the direction that the data is going to flow. So in this case,we list channel, we have the arrow and then the value that we wish to send into the channel.So notice that the arrow is pointing into the channel. But when we went to receive messagesfrom the channel, then the arrow is leading out of the channel. And so we’re going touse the same arrow syntax, but the channel is going to be added after the arrow insteadof before. And we can have multiple senders and receivers. As a matter of fact, it’s verycommon. As a matter of fact, it’s very common for one channel to be distributed among multiplego routines. And that way, you can have multiple data generators that are sending messagesinto the channel, as well as multiple data receivers. And that allows you to balancethe performance between senders and receivers. So if you can generate data 10 times as fastas you can process it, then you can create 10 times as many receivers.And that way youcan balance the workload out between senders and receivers. We then talked about how to restrict dataflow. Buying default, channels are bi directional constructs, so you can send and receive datainto a channel. Now very often what we want, though, is our go routines to be designedto handle channel data only in one direction. So we saw that we can do that by passing inthe channel. But then on the receiving side. So for example, in the argument list of thefunction, we can actually specify the direction that we can work with by again adding thatarrow, and we either add it before or after the chain keyword.Depending on what kindof channel that we want to make, we can make a send only channel by putting the arrow afterthe chain keyword, and we can make a receive only channel by adding the arrow before it.We then talk about buffered channels, and how buffered channels contain internal datastores that allow us to get around this limitation of channels that by default, a channel willblock the sender side until a receiver is available, and the receiver side will be blockeduntil a message is available to come out of the channel. So you can actually block a goroutine on the sending side or the receiving side of the channel. So if there’s no positionavailable in the channel to add the message, then the sending side will be blocked untila space does become available. And if there’s no message in the channel, then the receivingside is going to be blocked until a message becomes available for it to work with. Soin order to decouple that we can add an integer as a second argument to the main function.And that’s going to allow the channel to have an internal buffer to decouple your sendersand receivers, just in case there are situations where data is generated faster than it’s received.So just like it says here, we want to use buffered channels when sending and receivinghave asymmetric loading.So if we can generate messages faster than we can receive them,then a lot of times a buffered channel is a really good way to go. We then moved onto talk about four range loops, and specifically how to work with them with channels. And welearned that they basically work the same way. But there are a couple of subtle differences.The first thing is the first parameter that you’re going to receive from the four rangeloop when working with channels is the value itself, not the index, like we saw when wewere using for range loops over arrays, slices and maps. And we saw how we can use for rangeloops to monitor channel and process messages as they arrive. So the four range loop isjust going to keep pulling messages as they come in off the channel. And it’ll processthem as they come. Then when the channel gets closed, the four range loop is going to detectthat and it will go ahead and exit the loop. And finally, we talked about SELECT statements,and how they work kinda like switch statements, but they work only in the context of channels,and how they allow a go routine to monitor several channels at the same time.Now ifthey block if all channels are blocked, so if there’s no messages available on any channel,then the select statement will block by default. And then when a message comes in, it willgo ahead and process that on the proper case. If multiple channels receive value simultaneously,then the behavior is actually undefined. So because of the highly parallel nature of manygo applications, you can get into situations where messages arrive on two channels at virtuallythe same time. So one of those cases will get the nod from the Select block, but youcan’t be sure of which one’s going to get it. So there is no rule like in switch blockwhere the first one that matches is going to get it, it could be anyone. So the orderingof the cases in your SELECT statements really doesn’t matter from the standpoint of howthose conflicts are going to get resolved.Now if you do want a non blocking SELECT statement,remember that you can add that default case in there. So if there are no messages on anyof the monitored channels, then the default case will go ahead and fire and so the selectstatement will process and execution of the go routine will continue from there. Okay, so that wraps up what I have to talk aboutwith channels. And really it brings us to the end of the discussion that I have forthis introduction to go series for now. This is Mike vansickle wishing you luck in allof your gopher endeavors. Take care.

As found on YouTube

Leave a Reply

Your email address will not be published.