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
*/