Skip to content

Instantly share code, notes, and snippets.

@ncronquist
Last active July 15, 2019 04:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ncronquist/a4e9baf940d03d7e4d4135396de78e91 to your computer and use it in GitHub Desktop.
Save ncronquist/a4e9baf940d03d7e4d4135396de78e91 to your computer and use it in GitHub Desktop.
Golang Cheatsheet
# http://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 2

Introduction

References

Installation

Running Scripts

  • The Go Playground is an online repl that makes it easy to test small scripts
  • For a local repl, checkout the gore project

Program Structure

Every Go program is made up of packages. Programs start running in package main.

package main

import (
  "fmt"
  "math/rand"
)

func main() {
  fmt.Println("My favorite number is", rand.Intn(10).Seed(1023))
}

As you can see above, this program is using the fmt and math/rand packages. By convention, the package name is the same as the last element of the import path. For instance, the math/rand package comprises files that begin with the statement package rand.

Exporting Functions

In Go, a function is exported if it begins with a capital letter.

Go Comments

Comment Definition
// comment single-line comment
/* comment */ multi-line comment

Data Types

Variable type Definition
bool true/false
string represents a set of string values eg. "string" or string; strings are immutable
array numbered sequence of elements of a single type; a := [2]int{1, 3}
slice dynamically-sized, flexible view into the elements of an array; b := []int{1, 2, 3}
pointer holds the memory address of a value; var p *int
struct a collection of fields; the definition of an objects structure
map a key value object
function a unit of code that works on various inputs
interface set of method signatures
uint 32 or 64 bits depending on implementation
uint8 the set of all unsigned 8-bit integers (0 to 255)
uint16 the set of all unsigned 16-bit integers (0 to 65535)
uint32 the set of all unsigned 32-bit integers (0 to 4294967295)
uint64 the set of all unsigned 64-bit integers (0 to 18446744073709551615)
int same size as uint, 32 or 64 bits depending on implementation
int8 the set of all signed 8-bit integers (-128 to 127)
int16 the set of all signed 16-bit integers (-32768 to 32767)
int32 the set of all signed 32-bit integers (-2147483648 to 2147483647)
int64 the set of all signed 64-bit integers (-9223372036854775808 to 9223372036854775807)
uintptr an unsigned integer large enough to store the uninterpreted bits of a pointer value
byte alias for uint8
rune alias for int32, represents a Unicode code point
float32 the set of all IEEE-754 32-bit floating-point numbers
float64 the set of all IEEE-754 64-bit floating-point numbers
complex64 the set of all complex numbers with float32 real and imaginary parts
complex128 the set of all complex numbers with float64 real and imaginary parts

The int, uint, and uintptr types are usually 32 bits wide on 32-bit systems and 64 bits wide on 64-bit systems. When you need an integer value you should use int unless you have a specific reason to use a sized or unsigned integer type.

Strings

`abc`                // same as "abc"
`\n
\n`                  // same as "\\n\n\\n"
"\n"
"\""                 // same as `"`
"Hello, world!\n"
"日本語"
"\u65e5\U00008a9e"
"\xff\u00FF"
"\uD800"             // illegal: surrogate half
"\U00110000"         // illegal: invalid Unicode code point

These examples all represent the same string:

"日本語"                                 // UTF-8 input text
`日本語`                                 // UTF-8 input text as a raw literal
"\u65e5\u672c\u8a9e"                    // the explicit Unicode code points
"\U000065e5\U0000672c\U00008a9e"        // the explicit Unicode code points
"\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"  // the explicit UTF-8 bytes

Arrays

The type [n]T is an array of n values of type T. An arrays length is part of its type so arrays cannot be resized.

var a [10]int // variable a is array of 10 integers
func main() {
  var a [2]string
  a[0] = "Hello"
  a[1] = "World"
  // a == [Hello World]

  primes := [6]int{2, 3, 5, 7, 11, 13}
  // primes == [2 3 5 7 11 13]
}

Slices

A slice is a dynamically-sized, flexible view into the elements of an array. []T

Slices do not store data; they are like references to arrays.

Slices with no values are nil; var s []int; s == nil

Multiple ways to create slices:

  • Specifying the low and high indices of an array
    primes := [6]int{2, 3, 5, 7, 11, 13}
    var s []int = primes[1:4] // [3 5 7]
    
    // You can also omit the indices and the slice defaults to 0 and the length of the array
    var t []int = primes[:] // [2 3 5 7 11 13]
    var u []int = primes[:4] // [2 3 5 7]
    var v []int = primes[1:] // [3 5 7 11 13]
  • Slice literals are like arrays without the length
    • They automatically create an array and a slice that references it
      // Array literal
      [3]bool{true, true, false} // [true true false]
      
      // Slice literal; creates the same array as above and slice to reference it
      []bool{true, true, false} // [true true false]
      
      s := []struct {
        i int
        b bool
      }{
        {2, true},
        {3, false},
        {5, true},
        {7, true},
        {11, false},
        {13, true},
      } // [{2 true} {3 false} {5 true} {7 true} {11 false} {13 true}]
  • Creating a slice with make
    • The make function allocates a zeroed array and returns a slice that refers to that array
    a := make([]int, 5)    // len=5 cap=5 [0 0 0 0 0]
    b := make([]int, 0, 5) // b len=0 cap=5 []
    c := b[:2]             // c len=2 cap=5 [0 0]
    d := c[2:5]            // len=3 cap=3 [0 0 0]

Maps

A map is a key/value object store.

The zero value of a map is nil. A nil map has no keys, nor can keys be added.

The make function returns a map of the given type, initialized and ready for use.

type Vertex struct {
	Lat, Long float64
}

var m map[string]Vertex

m = make(map[string]Vertex)
m["Bell Labs"] = Vertex{
  40.68433, -74.39967,
} // map[Bell Labs:{40.68433 -74.39967}]

Map Literals

Map literals are like struct literals, but the keys are required.

type Vertex struct {
	Lat, Long float64
}

var m = map[string]Vertex{
	"Bell Labs": Vertex{
		40.68433, -74.39967,
	},
	"Google": Vertex{
		37.42202, -122.08408,
	},
} // map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]

// If the top-level type is just a type name, you can omit it from the elements of the literal.
type Vertex struct {
	Lat, Long float64
}

var m = map[string]Vertex{
	"Bell Labs": {40.68433, -74.39967},
	"Google":    {37.42202, -122.08408},
} // map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]

Mutating Maps

  • Insert or update an element in map m
    m[key] = elem
  • Retrieve an element
    elem = m[key]
  • Delete an element
    delete(m, key)
  • Test tha a key is present with a two-value assignment
    elem, ok = m[key]
    // If key is in m, ok is true. If not, ok is false.
    // If key is not in the map, then elem is the zero value of the map's element type.
    // If elem or ok have not yet been declared you could use a short declartation form.
    elem, ok := m[key]

Map Example

Return a map where each word has a count of how many times that word is in a string

package main

import (
	"strings"
	"golang.org/x/tour/wc"
)

func WordCount(s string) map[string]int {
	var res = make(map[string]int)
	var words []string
	words = strings.Split(s, " ")
	for _, v := range words {
		res[v] += 1
	}
	return res
}

func main() {
	wc.Test(WordCount)
}

Pointers

A pointer holds the memory address of a value.

The type *T is a pointer to a T value. Its zero value is nil.

var p *int

The & operator generates a pointer to its operand. The * operator denotes a pointers underlying value.

i := 42
p = &i // *p == 42
*p = *p + 1 // *p == i == 43

Structs

A struct is a collection of fields. (Like naming objects in JS?)

type Vertex struct {
  X int
  Y int
}

Struct fields are accessed using dot notation.

type Vertex struct {
  X int
  Y int
}

v := Vertex{1, 2}
v.X = 4
// v == {4, 2}

Pointers to structs can also be accessed with dot notation.

type Vertex struct {
  X int
  Y int
}

func main() {
  v := Vertex{1, 2}
  p := &v
  p.X = 1e9
  // v == {1000000000 2}
}

You can also create a struct by listing the values of is fields.

type Vertex struct {
	X, Y int
}

var v1 = Vertex{1, 2}  // {1 2}
var v2 = Vertex{X: 1}  // {1 0}
var v3 = Vertex{}      // {0 0}
var p  = &Vertex{1, 2} // &{1 2} has type *Vertex

Functions

Functions are values too. They can be passed around like other values.

Function values may be used as function arguments and return values.

func compute(fn func(float64, float64) float64) float64 {
	return fn(3, 4)
}

func main() {
	hypot := func(x, y float64) float64 {
		return math.Sqrt(x*x + y*y)
	}
	fmt.Println(hypot(5, 12)) // 13

	fmt.Println(compute(hypot)) // 5
	fmt.Println(compute(math.Pow))  // 81
}

Interface

Set of method signatures.

Example interface that implements function Length

package main

import (
	"fmt"
)

type Lengthsize interface {
	Length() int
}

func main() {
	var b Lengthsize
	var c Lengthsize
	g := MyString("Hello")
	h := MySlice{"hello", "world"}

	b = g // g MyString implements Length
	c = h // h MySlice implements Length

	fmt.Println(b.Length())
	fmt.Println(c.Length())
}

type MyString string
type MySlice []string

func (s MyString) Length() int {
	return len(s)
}

func (s MySlice) Length() int {
	return len(s)
}

Stringer Interface

The Stringer interface implemented by the fmt package allows you to implement a method on your types to format them as a string.

type Person struct {
	Name string
	Age  int
}

func (p Person) String() string {
	return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}

func main() {
	a := Person{"Arthur Dent", 42}
	fmt.Println(a) // Arthur Dent (42 years)
}

Type Assertion

Type assertion provides access to an interface value's underlying concrete value

t := i.(T)

var i interface{} = "hello"

s := i.(string)
fmt.Println(s) // hello

Type Switch

A type switch is a construct that permits several type assertions in series.

func do(i interface{}) {
	switch v := i.(type) {
	case int:
		fmt.Printf("Twice %v is %v\n", v, v*2)
	case string:
		fmt.Printf("%q is %v bytes long\n", v, len(v))
	default:
		fmt.Printf("I don't know about type %T!\n", v)
	}
}

func main() {
	do(21) // Twice 21 is 42
	do("hello") // "hello" is 5 bytes long
	do(true) // I don't know about type bool!
}

Type Conversions

Numeric Types

T(v) converts the value v to the type T.

Numeric conversion examples:

var i int = 42
var f float64 = float64(i)
var u uint = uint(f)

// Or

i := 42
f := float64(i)
u := uint(f)

String Conversion

String conversion requires the strconv package.

  • Convert string to integer with the Atoi function
    i, err := strconv.Atoi("-42")
  • Convert integer to string with Itoa function
    s := strconv.Itoa(-42)

Boolean Conversion

String too boolean conversion requires the strconv package.

To convert a string into a boolean use the ParseBool method. It returns the boolean value represented by the string. It accepts as parameter 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False. Any other value returns an error.

a, err := strconv.ParseBool("1") // true
b, err := strconv.ParseBool("t") // true
c, err := strconv.ParseBool("T") // true
d, err := strconv.ParseBool("TRUE") // true
e, err := strconv.ParseBool("true") // true
f, err := strconv.ParseBool("True") // true
g, err := strconv.ParseBool("0") // false
h, err := strconv.ParseBool("f") // false
i, err := strconv.ParseBool("F") // false
j, err := strconv.ParseBool("FALSE") // false
k, err := strconv.ParseBool("false") // false
l, err := strconv.ParseBool("False") // false

Basic Operators

Operators Usage
&& and
! not
== equal
!= not equal
< less than
    | greater than

<= | less than or equal

= | greater than or equal

  •     | addition
    
  •     | subtraction
    
  •     | multiplication
    

/ | division % | remainder (integers) & | bitwise AND | | bitwise OR ^ | bitwize XOR &^ | bit clear (AND NOT) << | left shift

   | right shift

Methods

Method Action
len returns the length of v, according to it's type len("Hello") == 5
cap returns the capacity v, according to it's type cap([4]{1,2,3,4}) == 4
append appends new elements to a slice s := []int{1,2}; s = append(s, 3, 4)
reflect.TypeOf returns type of data reflect.TypeOf("a") == string
reflect.DeepEqual determins if two values are deeply equal

Control Flow

If

if condition {
  // do something
} else {
  // do something different
}

// Example
if x > 0 {
  x++
} else {
  x = 1
}

If can start with a short statement before the condition, but any variables declared in that statement are only in scope of the if.

if v := math.Pow(x, n); v < lim {
  return v
}

For

sum := 0
for i := 0; i < 10; i++ {
  sum += i
}
// sum == 45

The init and post statements are optional in Go, so the for loop can be used as a while loop too.

sum := 1
for sum < 1000 {
  sum += sum
}

Range

range is another form of the for loops that iterates over a slice of map.

var nums = []int{1, 2, 4}

func main() {
	for i, v := range nums {
		fmt.Printf("%d - %d\n", i, v)
	}
}

// 0 - 1
// 1 - 2
// 2 - 4

Switch

Go only runs the selected case, not all the cases that follow, so the break statement required in some other languages is not needed in Go.

  • Example of switch with an init statement and a condition
    switch os := runtime.GOOS; os {
      case "darwin":
        fmt.Println("OS X")
      case "linux":
        fmt.Println("Linux")
      default:
        // freebsd, openbsd,
        // plan9, windows...
        fmt.Printf("%s\n" os)
    }
  • Example switch statement with no condition
    t := time.Now()
    switch {
    case t.Hour() < 12:
      fmt.Println("Good morning!")
    case t.Hour() < 17:
      fmt.Println("Good afternoon.")
    default:
      fmt.Println("Good evening.")
    }

Defer

A defer statement defers the execution of a function until the surrounding function returns.

func main() {
	defer fmt.Println("world")

	fmt.Println("hello")
}
// hello
// world

Deferred function calls are pushed onto a stack. When a function returns, its deferred calls are executed in last-in-first-out order.

func main() {
  fmt.Println("counting")

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

  fmt.Println("done")
}
// counting
// done
// 9
// 8
// 7
// 6
// 5
// 4
// 3
// 2
// 1
// 0

Console Printing

  • Print the type of a variable
    v := "42"
    t := 42
    fmt.Printf("v is of type %T\nt is of type %T\n", v, t)
    //v is of type string
    //t is of type int

Variables

Variables can be declared multiple ways in Go; var, :=, const

  • Using the var keyword and specifying a type
    var x int
    var a, b, c string
  • Using the short assignement statement := with implicit type
    • Note that this assignment opartor is only available inside a function
    k := 3
    isAlive := true
    i, hasAccount, taco := 42, true, "burrito"
  • Using the const keyword to create a constant
    • Constants can be character, string, boolean, or numeric values.
    • Constants cannot be declared using the := syntax
    const Pi = 3.14

Default Values (Zero Values)

Variables declared without an explicit initial value are given their zero value.

The zero value is:

numeric types: 0
boolean type: false
strings: "" (the empty string)

Functions

Functions are declared with the func keyword, can accept zero or more arguments, and can return zero or more values.

When two ore more consecutive named function parameters share a types, you can omit the type from all by the last.

x int, y int -> x, y int

Basic Structure

func name(a type, b type, ...) (return-type, return-type2, ...) {
  // Do something here and return a value of type return-type
}
  • Example with one return value

    func add(x int, y int) int {
      return x + y
    }
    
    // OR
    
    func add (x, y int) int {
      return x + y
    }
  • Example with multiple return values

    func swap(x, y string) (string, string) {
      return y, x
    }
  • Example with named return values

    • In the next example, we are using named return values and a "naked" return
    • Note that the return is not actually specifying what to return, but the values being set in the function match the names of the return values
    func split(sum int) (x, y int) {
      x = sum * 4 / 9
      y = sum - x
      return
    }

Keywords

The following keywords are reserved and may not be used as identifiers.

break        default      func         interface    select
case         defer        go           map          struct
chan         else         goto         package      switch
const        fallthrough  if           range        type
continue     for          import       return       var
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment