[Go] Range, Map, Functions

Range

The range form of the for loop iterates over a slice or map.

When ranging over a slice, two values are returned for each iteration. The first is the index, and the second is a copy of the element at that index.

1
2
3
4
5
6
7
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

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

You can skip the index or value by assigning to _.

1
2
for i, _ := row
for _, value := row

If you only want the index, you can omit the second variable.

for i := range pow

1
2
3
4
5
6
7
8
9
func main() {
pow := make([]int, 10)
for i := range pow {
pow[i] = 1 << uint(i) // == 2**i, why uint??
}
for _, value := range pow {
fmt.Printf("%d\n", value)
}
}

Maps

A map maps keys to values.

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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
type Vertex struct {
Lat, Long float64
}

var m map[string]Vertex

// Map literals are like struct literals, but the keys are required.
var n = map[string]Vertex{
"Bell Labs": Vertex{
40, -74,
},
"Google": Vertex{
37, -122,
},
}

// If the top-level type is just a type name, you can omit it from the elements of the literal.
var b = map[string]Vertex{
"Bell Labs": {40, -71},
"Google": {37, -122},
}

func main() {
m = make(map[string]Vertex)
m["Bell Labs"] = Vertex{
40, -74,
}
fmt.Println(m["Bell Labs"])
}

Mutate 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 that a key is present with a two-value assignment:

elem, ok := m[key]: ok == true if key is in m.

If key is not in the map, then elem is the zero value of the map’s element type.

1
2
3
4
5
6
7
8
func main() {
m := make(map[string]int)

m["Answer"] = 42 // {"Answer": 42}
m["Answer"] = 48 // {"Answer": 48}
delete(m, "Answer") // {}
v, ok := m["Answer"] // v: 0, ok: false
}

Functions

Functions are values too. They can be passed around just like other values. Function values may be used as function arguments and return values.

1
2
3
4
5
6
7
8
9
10
11
12
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))
fmt.Println(compute(hypot))
fmt.Println(compute(math.Pow))
}

Closures

Go functions may be closures. A closure is a function value that references variables from outside its body. The function may access and assign to the referenced variables; in this sense the function is “bound” to the variables.

For example, the adder function returns a closure. Each closure is bound to its own sum variable.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func adder() func(int) int {
sum := 0
return func (x int) int {
sum += x
return sum
}
}

func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
fmt.Println(
pos(i),
neg(-2*i)
)
}
}