VStamp

Learn GO Fast: Full Tutorial

Master Go in Under an Hour: Complete Golang Tutorial with API Build

TutorialAlex Mux728,341 viewsSep 4, 2023

A fast-paced, no-fluff guide to learning Go from basics to advanced concepts including concurrency, channels, generics, and building a RESTful API.

Golang
Go Programming Language
Variables
Data Types
Functions
Control Structures
Arrays
Slices
Maps
Strings
Runes
Bytes
Structs
Interfaces
Pointers
Goroutines
Channels
Generics
API Development
Concurrency
Middleware
Error Handling

Blurb

This tutorial by Alex Mux covers everything you need to learn Go quickly and effectively, from setting up your environment to building a fully functional API. Key points include:

  • Understanding Go's static and strong typing system and its advantages.
  • Mastering variables, constants, and basic data types including integers, floats, strings, and booleans.
  • Writing functions with parameters, multiple return values, and error handling.
  • Using arrays, slices, and maps with efficient memory management.
  • Deep dive into strings, runes, and UTF-8 encoding.
  • Defining and using structs and interfaces to model data and behavior.
  • Working with pointers for memory efficiency and function parameter passing.
  • Leveraging goroutines and channels for concurrency and safe data sharing.
  • Implementing mutexes and read-write mutexes to avoid race conditions.
  • Exploring generics to write reusable, type-safe functions and structs.
  • Building a RESTful API with authentication middleware, routing, and external package management.

This is a hands-on, practical guide with code examples and performance tips, perfect for developers wanting to learn Go fast without fluff.

Want the big picture?

Highlighted Clips

1.

Introduction to Go's Type System and Performance

Explains Go's static and strong typing, compiler advantages, and speed comparison with Python.

2.

Setting Up Go Environment and Project Initialization

Guide to installing Go, creating modules, packages, and writing your first Go program.

3.

Variables, Constants, and Basic Data Types

Detailed explanation of Go's variable declaration, data types, default values, and constants.

4.

Functions, Parameters, Multiple Returns, and Error Handling

How to define functions, pass parameters, return multiple values, and handle errors idiomatically in Go.

Introduction to Golang

Alex kicks off the tutorial by highlighting six key features of Go that make it a powerful language:

"Go is a statically typed language which means that you have to either declare variable types explicitly or they have to be inferred and these types cannot change afterwards at least not without type conversion."

He emphasizes Go’s static and strong typing, which prevents mixing incompatible types like integers and strings, unlike JavaScript. This leads to better error checking at compile time and improved developer experience with code completion and hints.

Alex contrasts Go’s compiled nature with interpreted languages like Python, showing a speed comparison where Go runs a loop 120 times faster:

"The execution time in Python took about 6 seconds in my machine and about 50 milliseconds in Go."

He also praises Go’s fast compilation time and built-in concurrency with goroutines, which will be explored later. The language’s simplicity and automatic garbage collection round out the main points.

Key points:

  • Statically and strongly typed: variables have fixed types.
  • Compiled to machine code, resulting in fast execution.
  • Fast compilation speeds improve developer workflow.
  • Built-in concurrency with goroutines.
  • Simple syntax and automatic memory management.

Constants, Variables, and Basic Data Types

Alex dives into declaring variables using the var keyword and explains Go’s type system in detail:

"You have to use every variable you declare. This is part of Go’s simplicity design philosophy."

He covers integer types (int8, int16, int32, int64) and warns about overflow errors that the compiler won’t catch at runtime, urging careful choice of types.

Unsigned integers allow storing larger positive numbers in the same memory size. Floating-point types (float32, float64) are explained with a nod to precision differences, and Alex links to a deeper video on floating-point storage.

Strings are introduced as UTF-8 encoded byte arrays, with a distinction between length in bytes vs. characters:

"Taking the length of a string is the number of bytes since Go uses UTF-8 encoding."

He introduces runes as Go’s character type, which represent Unicode code points, and shows how to get the character count properly.

Booleans are simple true/false types. Alex also explains default zero values for uninitialized variables and the shorthand := syntax for variable declaration with type inference.

Constants are immutable variables initialized at declaration, useful for fixed values like π.

Key points:

  • Variables declared with var or shorthand :=.
  • Integer types vary by bit size; watch for overflow.
  • Floats require explicit bit size; precision matters.
  • Strings are UTF-8 byte arrays; length counts bytes, not characters.
  • Runes represent Unicode characters.
  • Default zero values for uninitialized variables.
  • Constants are immutable and must be initialized.

Functions and Control Structures

Alex builds on the earlier main function example by defining custom functions with parameters and return values:

"To create a function in Go you use the func keyword followed by the name and parameters."

He shows how to return multiple values, a common Go pattern, using parentheses to specify multiple return types.

Error handling is introduced as a return value of type error, which is a built-in interface. Alex demonstrates checking for errors explicitly:

"If your function can encounter errors, have a return type of type error along with the values you're returning."

Control flow with if, else if, and else is covered, including logical operators && (and) and || (or). He notes Go’s syntax quirks like placing else on the same line as the closing brace.

Switch statements are shown as a cleaner alternative to multiple if-else chains, with implicit breaks after each case.

Key points:

  • Functions declared with func, can take parameters and return multiple values.
  • Error handling via explicit error return values.
  • Control flow with if, else if, else, and logical operators.
  • Switch statements with implicit breaks simplify multi-branch logic.

Arrays, Slices, Maps, and Loops

Alex explains arrays as fixed-length collections of elements of the same type stored contiguously in memory:

"An array is a fixed length collection of data all of the same type which is indexable and stored in contiguous memory locations."

He shows how to declare, initialize, and index arrays, and how memory addresses of elements are contiguous.

Slices are introduced as dynamic wrappers around arrays with flexible length and capacity. The append function is used to add elements, and Alex explains how Go reallocates underlying arrays when capacity is exceeded.

Maps are key-value stores, created with make or literals. He warns that accessing a non-existent key returns the zero value of the value type, so a second boolean return value is used to check existence.

Loops use the for keyword with range to iterate over arrays, slices, and maps. Go does not have a while loop but simulates it with a for loop without conditions.

Alex finishes with a performance test showing that pre-allocating slice capacity can speed up appending by 3x.

Key points:

  • Arrays: fixed size, contiguous memory.
  • Slices: dynamic, backed by arrays, can grow with append.
  • Maps: key-value pairs, return zero value if key missing, use second bool to check.
  • Loops: for with range for iteration; no while but can simulate.
  • Pre-allocating slice capacity improves performance.

Strings, Runes, and Bytes

Alex explores Go’s string internals using the example word "résumé" which contains non-ASCII characters.

He explains that strings are UTF-8 encoded byte arrays, so indexing a string returns a byte (uint8), not a character:

"When we index a string, we're actually indexing the underlying byte array."

He details UTF-8 encoding, showing how ASCII characters use one byte, while extended characters like 'é' use two bytes.

Using range over a string decodes UTF-8 properly and returns runes (Unicode code points), skipping over multi-byte characters correctly.

Alex shows how to convert strings to rune slices to work with characters directly.

He also covers string concatenation inefficiency due to immutability and introduces the strings.Builder type for efficient string building.

Key points:

  • Strings are UTF-8 byte arrays; indexing returns bytes.
  • UTF-8 uses variable-length encoding for characters.
  • range over strings decodes runes properly.
  • Runes represent Unicode code points (alias for int32).
  • Use strings.Builder for efficient concatenation.

Structs and Interfaces

Alex introduces structs as user-defined types with named fields of mixed types:

"Structs can hold mixed types in the form of fields which we can define by name."

He shows how to declare structs, initialize them with literals, and access fields.

Nested structs and anonymous fields are demonstrated, allowing embedding of one struct inside another.

Methods tied to structs are functions with a receiver argument, enabling object-oriented style behavior:

"Methods are functions which are directly tied to the struct and have access to the struct instance itself."

Interfaces are introduced as sets of method signatures that types can implement implicitly:

"An interface specifies a method signature and any type that has that method satisfies the interface."

Alex shows how interfaces enable writing functions that accept any type implementing the interface, increasing flexibility.

Key points:

  • Structs define custom types with fields.
  • Methods attach behavior to structs.
  • Interfaces define method sets; types implement them implicitly.
  • Interfaces enable polymorphism and generalization.

Pointers

Alex explains pointers as variables holding memory addresses rather than values:

"Pointers are variables which store memory locations rather than values like integers or floats."

He shows how to declare pointers with * and initialize them with new.

Dereferencing pointers with * accesses the value at the memory address.

He warns about nil pointers causing runtime errors if dereferenced without initialization.

Pointers can be created from existing variables using the & operator to get their address.

Alex highlights that slices internally use pointers to underlying arrays, so copying slices copies pointers, not data.

Passing pointers to functions avoids copying large data, allowing functions to modify original data.

Key points:

  • Pointers store memory addresses.
  • * dereferences pointers; & gets address of variables.
  • Nil pointers cause runtime errors if dereferenced.
  • Slices internally use pointers; copying slices copies references.
  • Passing pointers to functions saves memory and allows modification.

Goroutines

Alex introduces goroutines as lightweight concurrent functions:

"Goroutines are a way to launch multiple functions and have them execute concurrently."

He clarifies concurrency vs. parallelism: concurrency means multiple tasks in progress, parallelism means tasks running simultaneously on multiple cores.

Using the go keyword launches a function as a goroutine.

He demonstrates spawning multiple goroutines for database calls but notes the program exits before they finish unless synchronization is used.

The sync.WaitGroup is introduced to wait for all goroutines to complete by incrementing a counter on spawn and decrementing on completion.

Key points:

  • Goroutines enable concurrent execution.
  • go keyword launches goroutines.
  • Use sync.WaitGroup to wait for goroutines to finish.
  • Concurrency ≠ parallelism but often combined on multi-core CPUs.

Channels

Channels are explained as thread-safe communication pipes between goroutines:

"Channels hold data, are thread safe, and can block code execution until data is sent or received."

Unbuffered channels block the sender until the receiver is ready, preventing race conditions.

Alex shows how to send (ch <- value) and receive (value := <-ch) from channels.

He demonstrates iterating over channels with range and the importance of closing channels to avoid deadlocks.

Buffered channels allow sending multiple values without blocking until the buffer is full.

He builds a mock example checking chicken finger sales concurrently across stores, sending results through channels.

The select statement is introduced to wait on multiple channels and handle whichever receives data first.

Key points:

  • Channels enable safe communication between goroutines.
  • Unbuffered channels block sender until receiver is ready.
  • Buffered channels allow asynchronous sends up to capacity.
  • Closing channels signals no more data, preventing deadlocks.
  • select waits on multiple channels simultaneously.

Generics

Alex tackles generics, a way to write functions and types that work with multiple data types:

"Generics allow a function to receive additional parameters within square brackets, except instead of a value we're passing in a type."

He shows how to write a generic sumSlice function that works for int, float32, and float64 by specifying a type constraint.

The any type is introduced as a catch-all but with caveats since not all types support all operations (e.g., addition).

Generics can also be used with structs to create flexible types, such as a Car struct that can have either a gas or electric engine.

Alex prefers using generics mostly with functions but acknowledges their utility with structs.

Key points:

  • Generics enable type-parameterized functions and structs.
  • Type constraints restrict allowed types.
  • any is a generic placeholder for any type.
  • Generics reduce code duplication.
  • Useful for writing reusable, type-safe code.

Building an API in Go

Alex culminates the tutorial by building a RESTful API with authentication using Go’s ecosystem.

He outlines a project structure with folders for API specs, command entry point, and internal handlers.

Using the chi router package, he sets up routes and middleware for stripping slashes and authorization.

Authorization middleware checks query parameters and headers, returning JSON error responses with helper functions.

A database interface abstracts data access, implemented by a mock database with hardcoded user and coin data.

The API endpoint /account/coins returns coin balances for authorized users, decoding URL parameters with the gorilla/schema package.

Alex tests the API with Postman, showing successful and error responses.

Key points:

  • Use chi router for flexible HTTP routing.
  • Middleware handles authorization before endpoint logic.
  • Interfaces abstract database access for easy swapping.
  • JSON encoding/decoding for request and response structs.
  • Modular project structure for maintainability.

This tutorial by Alex Mux is a rapid yet thorough introduction to Go, covering foundational concepts, concurrency, data structures, generics, and practical API development, all with clear examples and explanations that keep the pace brisk and focused.

Key Questions

In Go, variable types must be declared explicitly or inferred at initialization and cannot change without conversion. Operations are type-checked strictly, preventing invalid operations like adding integers to strings.

Have more questions?

Analyzing video...

This may take a few moments.

Background illustration light mode

Ready to dive in?