Range

range iterates over elements in a variety of built-in data structures.

Arrays and Slice

s := []int{1, 2, 3}
for index, value := range s {
  fmt.Println(index, ": ", value)
}
/*
0: 1
1: 2
2: 3
*/

Maps

kvs := map[string]int{"apple": 1, "banana": 2}
for key, value := range kvs {
  fmt.Printf("%s -> %d\n", key, value)
}
// Iterates key-value pairs
for key := range kvs {
  fmt.Println("key: ", key)
}

Pointers

Just like pointers in C.

func swap(a, b *int) {
  // `*type` in the pointer of that type.
  c := *a
  *a = *b
  *b = c
  // Dereference like C
}
 
func main() {
  a, b := 1, 2
  swap(&a, &b)
  // Get address like C
  fmt.Println("a: ", a, "\n", "b: ", b)
}
/*
a: 2
b: 1
*/

String and Runes

A Go string is a Slice of bytes(uint8).
The language and std library treat it specially as container of text encoded in UTF-8

In Go, the concept of characters is called rune(int32), an integer represents a Unicode code point.

package main
import (
 "fmt"
 "unicode/utf8"
)
func main() {
 const s = "ハーロー、世界!"
 fmt.Println("Length(in bytes):", len(s))
 // Since string is a []byte, the `len()` will return the length of raw bytes stored.
 // Which usually is no less than the number of ch will return the length of raw bytes stored.
 // Which usually is no less than the number of characters in the string.
 
 for i := 0; i < len(s); i++ {
  fmt.Printf("%x ", s[i]) // Print in hex.
 }
 fmt.Println()
 // Indexing a string will return the raw byte valued at each index.
 
 fmt.Println("Number of characters:", utf8.RuneCountInString(s))
 // We can use `utf8.RuneCountInString()` to count the number of characters in a string.
 // The run-time depends on the length of the string,
 // since it needs to iterate the string and decode it sequentially, the complexity is O(n).
 
 for i, r := range s {
  fmt.Printf("%d: %#U\n", i, r) // Print in char.
 }
 // A range loop handle string especailly,
 // it will decode each rune.
 // So the index maybe jump, since some characters may take more than one byte.
 
 for i, w := 0, 0; i < len(s); i += w {
  runeValue, width := utf8.DecodeRuneInString(s[i:])
  fmt.Printf("%d: %#U\n", i, runeValue)
  w = width
  // Achieve the same result with `utf8.DecodeRuneInString()`,
  // which will return the decoded rune and the width of the rune in bytes.
 
  examineRune(runeValue)
  // Pass Rune as  a parameter.
 }
}
 
func examineRune(runeValue rune) {
 if runeValue == '' {
  // Values enclosed in single quotes are rune literals.
  fmt.Println("Found ハ")
 }
}
/*
Length(in bytes): 24
e3 83 8f e3 83 bc e3 83 ad e3 83 bc e3 80 81 e4 b8 96 e7 95 8c ef bc 81 
Number of characters: 8
0: U+30CF 'ハ'
3: U+30FC 'ー'
6: U+30ED 'ロ'
9: U+30FC 'ー'
12: U+3001 '、'
15: U+4E16 '世'
18: U+754C '界'
21: U+FF01 '!'
0: U+30CF 'ハ'
Found ハ
3: U+30FC 'ー'
6: U+30ED 'ロ'
9: U+30FC 'ー'
12: U+3001 '、'
15: U+4E16 '世'
18: U+754C '界'
21: U+FF01 '!'
*/

Enums

An enum is a type that has a fixed number of possible values, each with a distinct name.

Go doesn’t have an enum type as a distinct language feature, but enums are simple to implement using existing language idioms.

package main
import "fmt"
type Enum int
 
// Define a enum type underlying int,
// so that we can ensure type safety by compiler.
 
const (
 zero  Enum = iota // iota is a predeclared identifier representing successive untyped integer constants.
 one   Enum = iota // iota starts at 0 and increments by 1 for each line in the const block.
 two   Enum = iota // In essence, it is a compile-time row counter.
 three Enum = iota
) // zero is assigned 0, one is assigned 1 and so on.
 
/*
* We can also omit the iota in the subsequent lines, as it will automatically increment by 1 for each line.
* const (
*  zero Enum = iota // zero is assigned 0
*  one              // one is assigned 1
*  two              // two is assigned 2
*  three            // three is assigned 3
* )
* */
 
/*
* We can also use _ to skip a value in the enumeration.
* const (
*  _ Enum = iota // skip 0
*  one           // one is assigned 1
*  two           // two is assigned 2
*  three         // three is assigned 3
* )
* */
 
/*
* Make bit mask using iota is also common.(1 << iota)
* const (
*  one Enum = 1 << iota // read is assigned 1 (1 << 0)
*  two                  // write is assigned 2 (1 << 1)
*  four                 // execute is assigned 4 (1 << 2)
* )
 */
 
func (e Enum) String() string {
 // We can implement the fmt.Stringer interface to print these enum values as string,
 // so that we can disginguish them from regular integers when we print them.
 switch e {
 case zero:
  return "zero"
 case one:
  return "one"
 case two:
  return "two"
 case three:
  return "three"
 default:
  return "unknown"
 }
}
 
/*
* In fact, we can use the stringer tool to automatically generate the String() method for our enum type.
*
* //go:generate stringer -type=Enum
*
* type Enum int
*
* const (
*  ...
* )
*
* Then we can run `go generate` to generate the stringer code,
* which will create a file named enum_string.go with the String() method implemented.
* */
 
func main() {
 e1 := one
 e2 := two
 fmt.Println(e1)
 fmt.Println(e2)
}
/*
* one
* two
*/