DEV Community

Cover image for The Ultimate Go Cheatsheet πŸš€  - Best Go Concepts πŸ”₯
Garvit Motwani for World In Dev

Posted on • Updated on

The Ultimate Go Cheatsheet πŸš€ - Best Go Concepts πŸ”₯

Hey Devs, This is the most complete and well-structured Golang Cheatsheet you can find online!

So let's start.

Getting started

Introduction

Hello world

hello.go

package main

import "fmt"

func main() {
  message := greetMe("world")
  fmt.Println(message)
}

func greetMe(name string) string {
  return "Hello, " + name + "!"
}
Enter fullscreen mode Exit fullscreen mode
$ go build
Enter fullscreen mode Exit fullscreen mode

Or try it out in the Go repl, or A Tour of Go.

Variables

Variable declaration

var msg string
msg = "Hello"
Enter fullscreen mode Exit fullscreen mode

Shortcut of above (Infers type)

msg := "Hello"
Enter fullscreen mode Exit fullscreen mode

Constants

const Phi = 1.618
Enter fullscreen mode Exit fullscreen mode

Constants can be a character, string, boolean, or numeric values.

See: Constants

Basic types

Strings

str := "Hello"
Enter fullscreen mode Exit fullscreen mode
str := `Multiline
string`
Enter fullscreen mode Exit fullscreen mode

Strings are of type string.

Numbers

Typical types

num := 3          // int
num := 3.         // float64
num := 3 + 4i     // complex128
num := byte('a')  // byte (alias for uint8)
Enter fullscreen mode Exit fullscreen mode

Other types

var u uint = 7        // uint (unsigned)
var p float32 = 22.7  // 32-bit float
Enter fullscreen mode Exit fullscreen mode

Arrays

// var numbers [5]int
numbers := [...]int{0, 0, 0, 0, 0}
Enter fullscreen mode Exit fullscreen mode

Arrays have a fixed size.

Slices

slice := []int{2, 3, 4}
Enter fullscreen mode Exit fullscreen mode
slice := []byte("Hello")
Enter fullscreen mode Exit fullscreen mode

Slices have a dynamic size, unlike arrays.

Pointers

func main () {
  b := *getPointer()
  fmt.Println("Value is", b)
}
Enter fullscreen mode Exit fullscreen mode

{: data-line="2"}

func getPointer () (myPointer *int) {
  a := 234
  return &a
}
Enter fullscreen mode Exit fullscreen mode
a := new(int)
*a = 234
Enter fullscreen mode Exit fullscreen mode

Pointers point to a memory location of a variable. Go is fully garbage-collected.

See: Pointers

Type conversions

i := 2
f := float64(i)
u := uint(i)
Enter fullscreen mode Exit fullscreen mode

See: Type conversions

Flow control

Conditional

if day == "sunday" || day == "saturday" {
  rest()
} else if day == "monday" && isTired() {
  groan()
} else {
  work()
}
Enter fullscreen mode Exit fullscreen mode

See: If

Statements in if

if _, err := doThing(); err != nil {
  fmt.Println("Uh oh")
}
Enter fullscreen mode Exit fullscreen mode

A condition in an if statement can be preceded with a statement before a ;. Variables declared by the statement are only in scope until the end of the if.

See: If with a short statement

Switch

switch day {
  case "sunday":
    // cases don't "fall through" by default!
    fallthrough

  case "saturday":
    rest()

  default:
    work()
}
Enter fullscreen mode Exit fullscreen mode

See: Switch

For loop

for count := 0; count <= 10; count++ {
  fmt.Println("My counter is at", count)
}
Enter fullscreen mode Exit fullscreen mode

See: For loops

For-Range loop

entry := []string{"Jack","John","Jones"}
for i, val := range entry {
  fmt.Printf("At position %d, the character %s is present\n", i, val)
}
Enter fullscreen mode Exit fullscreen mode

See: For-Range loops

While loop

n := 0
x := 42
for n != x {
  n := guess()
}
Enter fullscreen mode Exit fullscreen mode

See: Go's "while"

Functions

Lambdas

myfunc := func() bool {
  return x > 10000
}
Enter fullscreen mode Exit fullscreen mode

Functions are first-class objects.

Multiple return types

a, b := getMessage()
Enter fullscreen mode Exit fullscreen mode
func getMessage() (a string, b string) {
  return "Hello", "World"
}
Enter fullscreen mode Exit fullscreen mode

Named return values

func split(sum int) (x, y int) {
  x = sum * 4 / 9
  y = sum - x
  return
}
Enter fullscreen mode Exit fullscreen mode

By defining the return value names in the signature, a return (no args) will return variables with those names.

See: Named return values

Packages

Importing

import "fmt"
import "math/rand"
Enter fullscreen mode Exit fullscreen mode
import (
  "fmt"        // gives fmt.Println
  "math/rand"  // gives rand.Intn
)
Enter fullscreen mode Exit fullscreen mode

Both are the same.

See: Importing

Aliases

import r "math/rand"
Enter fullscreen mode Exit fullscreen mode
r.Intn()
Enter fullscreen mode Exit fullscreen mode

Exporting names

func Hello () {
  Β·Β·Β·
}
Enter fullscreen mode Exit fullscreen mode

Exported names begin with capital letters.

See: Exported names

Packages

package hello
Enter fullscreen mode Exit fullscreen mode

Every package file has to start with package.

Concurrency

Goroutines

func main() {
  // A "channel"
  ch := make(chan string)

  // Start concurrent routines
  go push("Moe", ch)
  go push("Larry", ch)
  go push("Curly", ch)

  // Read 3 results
  // (Since our goroutines are concurrent,
  // the order isn't guaranteed!)
  fmt.Println(<-ch, <-ch, <-ch)
}
Enter fullscreen mode Exit fullscreen mode
func push(name string, ch chan string) {
  msg := "Hey, " + name
  ch <- msg
}
Enter fullscreen mode Exit fullscreen mode

Channels are concurrency-safe communication objects, used in goroutines.

See: Goroutines, Channels

Buffered channels

ch := make(chan int, 2)
ch <- 1
ch <- 2
ch <- 3
// fatal error:
// all goroutines are asleep - deadlock!
Enter fullscreen mode Exit fullscreen mode

Buffered channels limit the number of messages it can keep.

See: Buffered channels

Closing channels

Closes a channel

ch <- 1
ch <- 2
ch <- 3
close(ch)
Enter fullscreen mode Exit fullscreen mode

Iterates across a channel until its closed

for i := range ch {
  Β·Β·Β·
}
Enter fullscreen mode Exit fullscreen mode

Closed if ok == false

v, ok := <- ch
Enter fullscreen mode Exit fullscreen mode

See: Range and close

WaitGroup

import "sync"

func main() {
  var wg sync.WaitGroup

  for _, item := range itemList {
    // Increment WaitGroup Counter
    wg.Add(1)
    go doOperation(item)
  }
  // Wait for goroutines to finish
  wg.Wait()

}
Enter fullscreen mode Exit fullscreen mode

{: data-line="1,4,8,12"}

func doOperation(item string) {
  defer wg.Done()
  // do operation on item
  // ...
}
Enter fullscreen mode Exit fullscreen mode

A WaitGroup waits for a collection of goroutines to finish. The main goroutine calls Add to set the number of goroutines to wait for. The goroutine calls wg.Done() when it finishes.
See: WaitGroup

Error control

Defer

func main() {
  defer fmt.Println("Done")
  fmt.Println("Working...")
}
Enter fullscreen mode Exit fullscreen mode

Defers running a function until the surrounding function returns.
The arguments are evaluated immediately, but the function call is not ran until later.

See: Defer, panic and recover

Deferring functions

func main() {
  defer func() {
    fmt.Println("Done")
  }()
  fmt.Println("Working...")
}
Enter fullscreen mode Exit fullscreen mode

Lambdas are better suited for defer blocks.

func main() {
  var d = int64(0)
  defer func(d *int64) {
    fmt.Printf("& %v Unix Sec\n", *d)
  }(&d)
  fmt.Print("Done ")
  d = time.Now().Unix()
}
Enter fullscreen mode Exit fullscreen mode

The defer func uses the current value of d, unless we use a pointer to get the final value at end of the main.

Structs

Defining

type Vertex struct {
  X int
  Y int
}
Enter fullscreen mode Exit fullscreen mode
func main() {
  v := Vertex{1, 2}
  v.X = 4
  fmt.Println(v.X, v.Y)
}
Enter fullscreen mode Exit fullscreen mode

See: Structs

Literals

v := Vertex{X: 1, Y: 2}
Enter fullscreen mode Exit fullscreen mode
// Field names can be omitted
v := Vertex{1, 2}
Enter fullscreen mode Exit fullscreen mode
// Y is implicit
v := Vertex{X: 1}
Enter fullscreen mode Exit fullscreen mode

You can also put field names.

Pointers to structs

v := &Vertex{1, 2}
v.X = 2
Enter fullscreen mode Exit fullscreen mode

Doing v.X is the same as doing (*v).X, when v is a pointer.

Methods

Receivers

type Vertex struct {
  X, Y float64
}
Enter fullscreen mode Exit fullscreen mode
func (v Vertex) Abs() float64 {
  return math.Sqrt(v.X * v.X + v.Y * v.Y)
}
Enter fullscreen mode Exit fullscreen mode
v := Vertex{1, 2}
v.Abs()
Enter fullscreen mode Exit fullscreen mode

There are no classes, but you can define functions with receivers.

See: Methods

Mutation

func (v *Vertex) Scale(f float64) {
  v.X = v.X * f
  v.Y = v.Y * f
}
Enter fullscreen mode Exit fullscreen mode
v := Vertex{6, 12}
v.Scale(0.5)
// `v` is updated
Enter fullscreen mode Exit fullscreen mode

By defining your receiver as a pointer (*Vertex), you can do mutations.

See: Pointer receivers

Interfaces

A basic interface

type Shape interface {
  Area() float64
  Perimeter() float64
}
Enter fullscreen mode Exit fullscreen mode

Struct

type Rectangle struct {
  Length, Width float64
}
Enter fullscreen mode Exit fullscreen mode

Struct Rectangle implicitly implements interface Shape by implementing all of its methods.

Methods

func (r Rectangle) Area() float64 {
  return r.Length * r.Width
}

func (r Rectangle) Perimeter() float64 {
  return 2 * (r.Length + r.Width)
}
Enter fullscreen mode Exit fullscreen mode

The methods defined in Shape are implemented in Rectangle.

Interface example

func main() {
  var r Shape = Rectangle{Length: 3, Width: 4}
  fmt.Printf("Type of r: %T, Area: %v, Perimeter: %v.", r, r.Area(), r.Perimeter())
}
Enter fullscreen mode Exit fullscreen mode

References

Official resources

Other links

And remember to subscribe to our newsletter!

Top comments (2)

Collapse
 
s0xzwasd profile image
John Doe

Good article!

Collapse
 
garvitmotwani profile image
Garvit Motwani

Thanks for reading it πŸ™πŸ™