Learning Go – Day 2

Featured image by Egon Elbre

Happy Easter!

Maps

  • Used as a mapping between key-value pairs. Aka Dictionary in other languages.
  • Creating a map
// make(map[keyType]valueType)

nameToAge := make(map[string]int)

// short hand declaration
fileSizes := map[string]int{
	"file1.txt": 104,
	"file2.txt": 4224, //<-- notice the trailing comma!
}
  • Adding items to the map or updating existing values
nameToAge["jannie"] = 23
nameToAge["koos"] = 34
fmt.Println(nameToAge) // map[jannie:23 koos:34]

nameToAge["jannie"] = 42
fmt.Println(nameToAge) // map[jannie:42 koos:34]
  • Any comparable type is allowed to be used as a key type. Including your own “struct” types.
  • The zero value of a map is nil and maps have to be initialized first.
  • Getting items from a map.
ageForKoos := nameToAge["koos"]

// What about when the key does not exist?
// It returns the zero value of the type
fmt.Println(fileSizes["unknown"]) // 0
  • Checking if an item exists in the map.
value, ok := nameToAge["unknown"]
if ok {
... // key "unknown" existed and we received a value in value
}

// or to just check if key is present
_, exists := someMap[someKey]
if exists { ...
  • Iterating over the key-value pairs
for key, value := range nameToAge {
...
}
  • Map is unordered.
  • Use delete(map, key) function to delete an item from a map.
delete(nameToAge, "koos")

// No runtime error is raised if you delete a non existent key
// Also delete doesn't return a value to check if the key was deleted
delete(nameToAge, "no-error")
  • Use len(map) function to get the key count.
  • NOTE: Maps are reference types (unlike Swift). Meaning that if you assign a map to multiple variables (or pass to functions) then changes made to one will reflect to all of them (since they are references to the actual data).
  • Maps can not be compared using == operator. The == operator can only be used to check if the map is nil

Strings

  • Strings are implemented as a slice of bytes in Go.
  • string is the type.
  • Strings are unicode compliant and encoded as UTF-8.
name := "Andre Jacobs"
fmt.Printf("my name is %s\n", name)
  • Use len() to get the number of bytes in the string.
  • NOTE: Iterating over the bytes of a string is not the same as iterating over “characters” or unicode code points (as what Swift does).
  • To iterate over the unicode code points, you will use the rune type (alias to int32).
func printCharacters(s string) {  
    runes := []rune(s)
    for i := 0; i < len(runes); i++ {
        fmt.Printf("%c ", runes[i])
    }
}

// A much better way is to use range
for index, rune := range s {
...
}
  • Creating a string from a slice of bytes.
byteSlice := []byte{0x43, 0x61, 0x66, 0xC3, 0xA9}
str := string(byteSlice)
  • Creating a string from a slice of runes.
runeSlice := []rune{0x0053, 0x0065, 0x00f1, 0x006f, 0x0072}
str := string(runeSlice)
  • Use RuneCountInString() function from package “unicode/utf8” to get the number of unicode “characters” in a string.
  • You can use == to check for equality. (May assumption is Go just compares the bytes and no the grapheme clusters like Swift does).
  • You can concatenate strings using + operator. You can also use fmt.Sprintf function.
  • String are immutable.

Pointers

  • Quick recap: A pointer is a variable that stores an address to some location in memory (that can then be mapped to a type).
  • Declared using *T.
  • Use & to get the address of a variable.
b := 255
var a *int = &b // create a pointer to b
fmt.Printf("Type of a is %T\n", a) // Type of a is *int
fmt.Println("address of b is", a) // address of b is 0xc000018030
  • Zero value of a pointer is nil.
  • Allocate a new instance and assign to a pointer using new function.
  • Dereference using * just like C.
p := new(int)
fmt.Printf("%T\n", p) // *int
fmt.Println(p) // 0xc000018038
fmt.Println(*p) // 0

*p = 42
fmt.Println(*p) // 42
  • Pointers can be passed as function arguments.
  • Pointers can also be returned as the result type for a function.
// What do you think this code will do?
func spideySense() *int {
    i := 5
    return &i
}

// Go is smart enough to save you from the C pitfalls here and
// allocates i on the heap!
  • It is more Go idiomatic to pass slices of arrays to functions (instead of passing a pointer to an array).
  • Go does not support pointer arithmetic like C does.