The Go Handbook – Learn Golang for Beginners

Go, also known as Golang, is a modern programming language developed by Google engineers Robert Griesemer, Rob Pike, and Ken Thompson. First released in 2009, Go has quickly risen in popularity among developers. According to the Stack Overflow 2020 Developer Survey, Go is the 5th most loved programming language, with 62.3% of respondents expressing interest in continuing to develop with it.

Go ranks #5 among most loved programming languages in the Stack Overflow 2020 Developer Survey

So what makes Go so attractive to programmers? In this comprehensive beginner‘s guide, we‘ll explore the guiding principles behind Go‘s design and walk through the key features that make the language so productive and enjoyable to use. By the end, you‘ll have a solid foundation to start building your own applications with Go.

Why Go Was Created

To understand Go, it helps to look at the context in which it was created. Back in 2007, Google was facing challenges scaling its large codebases written in C++ and Java. Build times were slow, the languages were overly complex, and writing concurrent programs was difficult and error-prone.

Go was designed to address these issues while still retaining the positive aspects of languages like C. Rob Pike, one of Go‘s creators, explained the motivation behind the language in a 2012 interview:

"The goals of the language and its accompanying tools were to be expressive, efficient in both compilation and execution, and effective in writing reliable and robust programs."

To achieve these goals, the Go team prioritized the following principles:

  • Simplicity: Go has a minimal set of features and eschews "extraneous garbage" like header files and explicit type hierarchies. The grammar is compact enough to hold in your head, which reduces cognitive load while programming.

  • Readability: Go emphasizes readability with clean, concise syntax and naming conventions like CamelCase for exported identifiers. Gofmt, the built-in formatting tool, enforces a consistent style across all Go code.

  • Maintainability: By keeping features orthogonal and independent, Go makes it easy to understand and modify existing programs. Refactoring is aided by fast compile times.

  • Efficiency: Both in compilation speed and run-time performance, Go is competitive with C and C++. Its design keeps programmers productive while still being suitable for system programming domains.

  • Concurrency: Go makes concurrent programming tractable with goroutines and channels as first-class language primitives. This allows developers to effectively utilize multi-core hardware without complex lock-based synchronization.

Compared to dynamic languages like Python, Go is much more performant and has better tooling for large codebases. Meanwhile, Go eliminates much of the complexity and verbosity of languages like Java and C++. For example, Go has no classes, exceptions, function overloading, or inheritance – which makes it faster to learn and easier to read.

Rising Popularity

Since its 1.0 release in 2012, Go has seen widespread adoption by developers around the world. High-profile users include Google, Uber, Twitch, Dropbox, Kubernetes, and Hugo. Go consistently ranks as one of the top 10 most popular languages on GitHub by pull request and is a common choice for cloud infrastructure, web servers, DevOps tools, and data processing pipelines.

Go ranks among the top 10 languages by pull requests on GitHub

What‘s driving this growth? In StackOverflow‘s 2020 survey, developers cited Go‘s performance, simplicity, reliability, built-in concurrency, and easy learning curve as its most-liked aspects. The forward compatibility promise of Go 1 means that old code continues to work with new releases, giving developers confidence to build large, long-lived projects.

Enterprise adoption of Go has also accelerated, with companies like American Express, Target, Capital One, and The New York Times choosing Go for critical workloads. In The Go Developer Survey 2020, 76% of respondents said they use Go at work, and 66% said Go is critical to their company‘s success.

Language Basics

Now that we‘ve covered the background, let‘s dive into the specifics of the Go language, starting with the basics.

Variables and Types

Go is statically typed, which means every variable has a type known at compile-time. Variable declarations have the following syntax:

var x int 
var s string
var f float64

You can also use the short variable declaration operator := to infer the type from the value:

x := 10 // int 
s := "hello" // string
f := 3.14 // float64

Go has a variety of built-in types, including:

  • Booleans: bool
  • Numeric types: int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64
  • String type: string
  • Array types: [n]T where n is length and T is element type
  • Slice types: []T
  • Map types: map[K]V where K and V are key and value types
  • Pointer types: *T
  • Function types: func(T) U where T is input types and U is output types
  • Interface types: interface { M(T) U } where M is method name

You can also define your own types using the type keyword:

type Duration int64
type Person struct {  
    Name string
    Age  int
}

Functions

Functions in Go use the func keyword followed by name, parameters, return types, and body:

func add(a int, b int) int {
    return a + b
}

Multiple return values are supported and often used to return a result and error:

func divmod(a, b int) (int, int, error) {
    if b == 0 {
        return 0, 0, errors.New("division by zero")
    }
    return a / b, a % b, nil
}

Variadic functions can take a variable number of arguments:

func sum(nums ...int) int {
    total := 0
    for _, n := range nums {
        total += n 
    }
    return total
}

fmt.Println(sum(1, 2, 3)) // 6

Functions are first-class values in Go and can be passed as arguments, returned, and assigned to variables:

func compute(op func(int, int) int) int {
    return op(2, 3) 
}

add := func(a, b int) int { return a + b }
fmt.Println(compute(add)) // 5

Control Flow

Go provides standard control flow statements like if, for, and switch.

If statements can include a short initialization statement before the condition:

if err := process(); err != nil {
    return err
}

For loops come in several varieties:

// basic for loop
for i := 0; i < 10; i++ {
    fmt.Println(i)
}

// while loop  
for x < 100 {
    x *= 2
}

// infinite loop
for {
    // do something forever
}

// range loop  
fruits := []string{"apple", "banana", "cherry"}
for i, fruit := range fruits {
    fmt.Printf("%d: %s\n", i, fruit) 
}

Switch statements provide multi-way branching:

switch os := runtime.GOOS; os {
case "linux":
    fmt.Println("Linux.")
case "darwin": 
    fmt.Println("OS X.")
default:
    fmt.Printf("%s.\n", os)
}

Unlike other C-like languages, Go only runs the selected case by default. It doesn‘t fall through to the next case unless you explicitly use the fallthrough keyword.

Structs and Methods

Go has no classes, but you can define custom types called structs which can have methods:

type rect struct {
    width  float64
    height float64
}

func (r rect) area() float64 {
    return r.width * r.height 
}

r := rect{width: 10, height: 5}
fmt.Println(r.area()) // 50

Methods with pointer receivers can modify the underlying struct instance:

func (r *rect) scale(factor float64) {
    r.width *= factor
    r.height *= factor
}

r.scale(0.5)
fmt.Println(r.area()) // 12.5  

Interfaces

Interfaces in Go specify methods that a concrete type must implement. This allows you to write generic, decoupled code.

type geometry interface {
    area() float64
    perim() float64
}

func measure(g geometry) {
    fmt.Println(g)
    fmt.Println(g.area())
    fmt.Println(g.perim())
}

type rect struct {
    width, height float64
}

func (r rect) area() float64 {
    return r.width * r.height
}

func (r rect) perim() float64 {
    return 2*r.width + 2*r.height
}

r := rect{width: 3, height: 4}
measure(r)

This prints:

{3 4}
12
14

Any type that implements the area() and perim() methods automatically satisfies the geometry interface and can be passed to measure().

Concurrency

Go has first-class support for concurrent programming with goroutines and channels. Goroutines are lightweight threads of execution that are managed by the Go runtime:

func f(msg string) {
    fmt.Println(msg)
}

go f("goroutine") // starts a new goroutine

Channels are typed conduits for sending and receiving values between goroutines:

func worker(id int, jobs <-chan int, results chan<- int) {
    for job := range jobs {
        fmt.Printf("worker %d processing job %d\n", id, job)
        results <- job * 2
    }
}

jobs := make(chan int, 100)
results := make(chan int, 100)

for i := 1; i <= 3; i++ {
    go worker(i, jobs, results)
}

for i := 1; i <= 9; i++ {
    jobs <- i 
}
close(jobs)

for i := 1; i <= 9; i++ {
    fmt.Println(<-results)
}

This example showcases a worker pool pattern where multiple goroutines consume jobs from an input channel, process them, and send results on an output channel. The <-chan and chan<- annotations specify a receive-only and send-only channel respectively.

The select statement allows a goroutine to wait on multiple channel operations simultaneously:

select {
case msg := <-messages:
    fmt.Println(msg)
case <-time.After(1 * time.Second):
    fmt.Println("timeout")  
}

Tools and Ecosystem

Go ships with a powerful set of command line tools for development tasks:

  • go build compiles packages and dependencies
  • go run compiles and runs a program
  • go fmt formats code according to Go conventions
  • go get downloads and installs packages
  • go test runs tests and benchmarks
  • go doc shows documentation for a package or symbol
  • go vet reports potential errors in packages

The Go toolchain also integrates with IDEs and editors, providing features like code completion, jump to definition, refactoring, and debugging. Popular Go plugins exist for VS Code, IntelliJ, Vim, and Emacs.

Go has a thriving open source ecosystem with libraries for every domain including:

  • Web frameworks: Gin, Echo, Revel
  • Databases: SQLBoiler, GORM, pgx
  • Data processing: gonum, Gleam, Pachyderm
  • Machine learning: GoLearn, Gorgonia, Goml
  • Devops: Docker, Kubernetes, Terraform

You can find thousands of high-quality packages at pkg.go.dev.

Learning Resources

Here are some of the best free and paid resources for learning Go:

  • A Tour of Go (Free) – Browser-based introduction to Go‘s syntax and features
  • Go by Example (Free) – Code snippets covering common tasks in Go
  • Gophercises (Free) – Practice Go by completing 20 mini-projects
  • Ultimate Go (Paid) – Video course by Go trainer Bill Kennedy
  • Let‘s Go (Paid) – Book on building production-ready web services in Go
  • Learn Go with Tests (Free) – Test-driven development in Go
  • Gophers Slack (Free) – Chat with over 100k Go developers
  • Golang Weekly (Free) – Newsletter with the latest Go articles and news

Conclusion

I hope this guide has given you a comprehensive overview of Go programming. To recap, we covered:

  • Go‘s origin, philosophy, and guiding principles
  • Basic syntax for variables, functions, control flow, and types
  • Unique Go features like structs, interfaces, goroutines and channels
  • Go‘s ecosystem of tools and libraries
  • Resources for continuing your Go learning journey

What attracts developers to Go is its combination of simplicity and power. Go is easy to learn and read, yet suitable for everything from web services to systems programming. Its excellent tooling, backwards compatibility guarantee, and fast compile times lead to a highly productive development workflow. Concurrency is tractable with goroutines and channels as first-class primitives.

As the Go community likes to say, Go makes programming fun again! There‘s a reason so many developers are switching to Go. Whether you‘re a seasoned programmer looking to level up your skills or completely new to coding, I highly recommend giving Go a try.

Similar Posts