 This is going to be an introduction to the Go language and it programmers having at least a basic familiarity with JavaScript It may also help to have basic familiarity with C, but that is not expected I'm not going to cover every detail of Go, but I'll hit all the major concepts fairly thoroughly Go is quite young first released publicly in late 2009 The primary three authors of the language are Rob Pike Ken Thompson and Robert Griezemer all developers at Google Both Rob Pike and Ken Thompson were previously well known for their involvement in the development of Unix and Thompson was one of the primary authors of the C language In many ways Go is targeted as a successor to C and C plus plus, but Go is a higher level language Most notably Go is garbage collected in memory safe Consequently unlike C and C plus plus Go is generally inappropriate for low-level code and very high performance code such as in operating systems and graphically intensive games Where Go excels is in concurrency thanks to two features, Go Routines and Channels Go Routines allows to create many separate threads of execution without the usual overhead and Channels give us a simple mechanism to communicate between our threads and synchronize them Along with native compilation these features make Go particularly well suited for server code and that is where Go has most commonly been used Beyond servers Go is surprisingly well suited for small scripts that otherwise would be written in Python Ruby the shell or other dynamic languages Even though Go is statically typed it largely avoids the burdens usually associated with statically typed languages Unlike most recent languages Go is not object-oriented at least not in the classical sense Instead of requiring us to define a hierarchy of types in our programs Go allows us to express ad hoc relationships between types with what are called interfaces as we'll see an interface defines a set of methods and any type that implements all of the methods of an interface is Considered to automatically implement that interface as well The practical result is that Go programmers don't have to worry about building and managing complex type hierarchies What I most appreciate about Go is that the language stringently avoids complexity in both the rules of the language and in its tool chain The creators of Go have resisted the usual temptation to pile on more and more features Allowing the users of Go to think about the problems they want to solve instead of wasting time thinking about the language Just like in JavaScript variables in Go are declared by var statements What's different in Go is that we specify a type after the variable name Here we specify that this variable foo is of type string and so the Go compiler only allows us to assign strings to foo Not any other kind of value This is static typing the programmer must declare a type for every variable and the compiler then enforces that type Specifying the types of every variable tends to make our code verbose But Go allows a variables type to be left in the third if we initialize the declaration Here the compiler infers that foo is a string variable because we initialize it with a string in the declaration In any subsequent assignments the compiler requires that we sign only strings to foo just like if we had explicitly declared the type As a further convenience we can leave out the word var if we put a colon before the equal sign Unlike in JavaScript variables in Go may not be declared more than once in a scope Here the compiler will complain that we are redeclering foo To fix this we should use the colon only in the first assignment in truth The compiler needn't be so picky But the authors of Go didn't want programmers to habitually use colon equals when they only need assignment because that habit might lead to unintended declarations Another difference from JavaScript is that control flow constructs like if-else and loops are each their own scope Here we declare a variable y inside this if and so y only exists inside the if If we move the declaration of y above the if it now exists both within the if and without When we declare a variable y both outside the if and also within then these are two separate variables They're just happened to share the same name outside the if y refers to the outer variable Inside the if y refers to the inner variable So here the colt foo is past the value of the outer y which was last assigned to 5 Aside from strings Go also has a boolean type called bool bool of course has two values true and false Where things get complicated is with numbers in JavaScript We have just one number type which is represented as 64 bit floating point But in go we have several different number types with different sizes for integers We have four sizes eight bits 16 bits 32 bits or 64 bits for floating point numbers We have two sizes 32 bits and 64 bits If you don't understand the distinction between integers and floating point or if you don't understand the significance of the number of bits You should watch my earlier video called numbers as bits The short explanation is that integers represent only whole numbers while floating point values have a fractional component like 3.47 The more bits to represent the number the larger the range of possible values For example an 8-bit integer can only represent the numbers negative 128 up to positive 127 But a 16-bit integer can represent the values from negative 32,768 up to positive 32,767 Go also has unsigned integer types which represent only positive values including zero For example an 8-bit unsigned integer can represent integers from zero up to positive 255 Complex numbers you may remember from math class are the sum of two components one of which is imaginary In Go these two parts are represented as two floating point numbers So a complex 64 is made up of two 32-bit floating point numbers and a complex 128 is made up of two 64-bit floating point numbers You won't need complex numbers unless you do certain kinds of mathematics, but I mentioned them here for completeness Finally we have these five types which are actually equivalent to other existing types a plain int is equivalent to either an int32 or an int64 On 32-bit platforms 32-bit integers tend to be more efficient to use But on 64-bit platforms 64-bit integers tend to be more efficient So the size of an int depends upon the platform for which we're compiling Unless you have good reason to use some other type it should be your default choice to represent a number Uint PTR as an unsigned integer pointer is an unsigned integer type that is large enough to store a memory address Memory address is varying size between platforms. So the size of Uint PTR depends upon which platform we're compiling for The byte type is merely an alias for Uint 8 and the rune type is merely an alias for int32 a byte of course is 8 bits and rune is a unicode term for a single character These aliases exist simply to make the intent of some code more clear Now you may be wondering what happens when the results of number operations Produce values too big or too small for the number type range Well in general the result will wrap around for example the max value of a Uint 8 is 255 And so if we add 1 to 255 the value overflows to 0 and if we add 3 to 255 the value overflows to 2 Conversely if we subtract 1 from the smallest Uint 8 value, which is 0 we get underflow to 255 If we subtract 10 from 4 we get underflow to 250 The same thing happens for all integer types just with different min and max values for an int16 For example, we get overflow when we exceed 32,767 and we get underflow when we go below negative 32,768 For floating point numbers, it's a different story rather than overflow a floating point operation that should return a result Larger than the greatest possible value instead returns a special value plus infinity Likewise a floating point operation that we should return a result lesser than the smallest possible value Instead returns a special value negative infinity Actually, the floating point story is more complicated than this because of rounding and precision issues, but we won't discuss those details here Suffice it to say that you should be careful when dealing with values at the extremities of the number type ranges And in case you ever need to do math with arbitrary precision the Go standard library provides a package called math slash big for that purpose Also understand that Go is serious about these number types all being separate types You might think we should be able to assign this int32 variable bar to the int64 variable foo Because all int32 values fit in the range of an int64, but Go will reject this assignment To satisfy the compiler we have to explicitly convert the int32 value to an int64 and only then is the assignment allowed Similarly, we cannot perform arithmetic on two values of different types instead We must explicitly convert the two values to a matching type here We must get the n64 equivalent of bar if you want to add bar to foo When converting from an int32 to an int64 the value is preserved But in some conversions the value may end up distorted when converting from an int to a uint8 For example many int values do not fit in range of a uint8 And so the converted value won't necessarily be the same Here converting the int value 500 to uint8 produces the value 244 by truncating the int down to its least significant 8 bits When declaring number variables understand that number literals themselves do not have any particular type And so can be used in assignments to any kind of number However, when a variable's type is inferred from a number literal integer literals default to int And floating point literals default to float64 Lastly, be clear that int is always a different type than int32 or int64 Even when an int has the same underlying representation As far as the compiler is concerned, they are different sorts of things Go function definitions should look quite familiar The only difference from JavaScript here is that we write funk instead of function Unlike in JavaScript however, this function foo can only be called with zero arguments And because foo doesn't specify any return type, it cannot return anything In contrast, this version of function foo takes two parameters, a string and a boolean, and returns an int Whereas a function in dynamic languages like JavaScript can return different kinds of values A function in a static language like go has to declare what kind of value it returns Having declared this function foo to return an int, the compiler will object if we attempt to return a string or some other kind of value Likewise, the compiler will complain if we attempt to call this function with the wrong types of arguments or the wrong number of arguments Even when we pass to a function values from variables or values returned by function calls The compiler will know if the types match the function parameters because all variables have a declared type And all functions have a declared return type A unique feature of go is that functions can be declared to return more than one value Here the function foo returns both an int and a string When we call this function, the returned int is assigned to A and the returned string is assigned to B Multi-return functions cannot be called where a single value is expected So the call here is invalid because the context expects just a single number Often when calling a multi-return function, we don't care about all the returned values As a convenience, underscore is a special variable name which doesn't actually get assigned to any value When you assign to underscore, the value is effectively discarded So you can only use underscore to discard values from multiple returns, we otherwise can't use it as a variable I mentioned earlier that go is picky about re-declaring variables Well, go is less picky in this special case Here we are effectively re-declaring the variable A in a multi-value assignment, but the compiler won't complain To make go code look prettier and less cluttered, go allows us to leave most semicolons implicit What happens is that the compiler will insert semicolons at the end of any line ending with a literal and identifier The reserved words break, continue, fall through, and return The increment and decrement operators and the end delimiters, which are end-parentheses and curly-brace and end-square brackets Note that the go spec considers types like int and float64 to be identifiers So the compiler will insert semicolons after those words when they're at the end of a line In this example, the compiler will insert four semicolons One after the number literal three, one after the end curly-brace, and two after these end-parentheses Perhaps surprisingly, the grammar of go actually does expect a semicolon after a function declaration We just usually never see it because we leave it implicit In this case, the compiler will insert three semicolons, two after the end parentheses, and one after the end curly-brace The semicolon insertion rules effectively prevent us from formatting our code in certain ways For example, putting our opening curly-braces on their own line will cause semicolons to be inserted in places where the compiler doesn't want them Another oddity of go syntax is that it allows you to put a comma after the last argument to a function This is useful when we spread a function call onto multiple lines because then a comma after the last argument will prevent insertion of an unwanted semicolon Here we declare variable a to be an array of four ints Unlike in JavaScript, arrays and go have a fixed size that must be specified upon creation and a single array can only hold values of one type So here would we assign a string to index three of this array of ints The compiler will complain that we are assigning the wrong type Likewise, we'll get an error if we attempt to assign to an out-of-bounds index In this case, because the out-of-bounds index is specified by constant, the compiler will catch the error If we specify the out-of-bounds index with a variable, however, the error will not be caught until the assignment is attempted at runtime Also understand that the size of each array must be known at compile time and so we can specify array sizes only with constants, not with variables or other expressions that can be evaluated only at runtime Here we create another variable which is an array of four ints Assigning array a to array b copies all of the values of a to b Understand that the variables here are themselves arrays. They store the values directly This is different from JavaScript where every variable is merely a reference to some object elsewhere in memory In JavaScript, assigning a to b would make a and b both reference the same array object But here in go, a and b are always two separate arrays with separate values To assign one array to the other, they of course must be the same type For example, an array of u ints is not the same as an array of ints, so this assignment is illegal The size of an array is an integral part of its type, so an array of three ints is not the same type as an array of four ints Here the function foo takes its argument an array of four ints and in the function assigns to the first index of the array Be clear, however, that the array a is copied to b and so modifications of b don't affect a They are two separate arrays Given any type in the language, we can make an array of it, even other arrays So here we have an array of two arrays of three ints, a so called multidimensional array Again, unlike JavaScript, the arrays are fixed in size and so we cannot assign the indexes out of bounds Also, unlike JavaScript, the elements of an array in go are always stored contiguously in memory If we have an array of arrays, that means we have multiple arrays stored next to each other in memory Here for example is what an array of two arrays of three ints looks like in memory And here is what an array of two arrays of three arrays of two ints looks like in memory However, the elements of an array are not always directly contiguous In some cases the compiler will put unused bytes of padding in between elements of an array So that the elements better align to four and eight byte boundaries Effectively trading away memory efficiency for better processing efficiency