0%

A Tour Of Go/ More Types/ Structs, Slice, Map

More Types: Structs, Slice, Map

Pointer

A pointer holds the memory address of a value.

The type *T is a pointer to a T value.
Zero value of point is nil.

1
var p *int // is nil now

The & operator generates a pointer to its operand.

1
2
i := 42
p = &i

The * operator denotes the pointer’s underlying value.

1
2
fmt.Println(*p) // read i through the pointer p
*p = 21 // set i through the pointer p

This(What ? 指的是什麼? 不懂) is known as “dereferencing” or “indirecting”.

Structs

A struct is a collection of fields.

1
2
3
4
type Vertex struct {
X int
Y int
}

Struct fields are accessed using a dot.

1
2
3
v := Vertex{1, 2}
v.X = 4
fmt.Println(v.X)

Pointers to structs

To access the field X of a struct when we have the struct pointer p we could write (*p).X.

However, that notation is cumbersome, so the language permits us instead to write just p.X, without the explicit dereference.

1
2
3
4
5
v := Vertex{1, 2}
ptV := &v
ptV.X = 3
(*ptV).Y = 4
fmt.Println(ptV)

Struct Literals

A struct literal denotes a newly allocated struct value by listing the values of its fields.

1
2
3
4
5
6
var (
v1 = Vertex{1, 2} // has type Vertex
v2 = Vertex{X: 1} // Y:0 is implicit
v3 = Vertex{} // X:0 and Y:0
p = &Vertex{1, 2} // has type *Vertex
)

Array

The type [n]T is an array of n values of type T.

An array’s length is part of its type, so arrays cannot be resized.

1
2
3
4
5
6
7
var a [2]string
a[0] = "Hello"
a[1] = "World"
fmt.Println(a[0], a[1])
fmt.Println(a)

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

Slices

An array has a fixed size.
A slice is a dynamically-sized, flexible view into the elements of an array.

Q: In practice, slices are much more common than arrays., why ?

A: use slice, we don’t have to worry about the fiexed size of an array.
Go will handle this for us

1
2
3
primes := [6]int{2, 3, 5, 7, 11, 13}
var s []int = primes[1:4] //from 1 to 3
fmt.Println(s) // [3,5,7]

Slices are like references to arrays

A slice does not store any data, it just describes a section of an underlying array.

Changing the elements of a slice modifies the corresponding elements of its underlying array.

Other slices that share the same underlying array will see those changes.

Slice literals

A slice literal is like an array literal without the length.

array literal:

1
[3]bool{true, true, false}

creates the same array as above, then builds a slice that references it:

1
[]bool{true, true, false}

Slice defaults > you may omit the high or low bounds

default:
low bound: 0
high bound: length

1
2
3
4
5
6
7
var a [10]int

// these slice expressions are equivalent:
a[0:10]
a[:10]
a[0:]
a[:]

Q:問題 感覺 slice 之後的範圍怪怪的 > 解答見下一個小節

1
2
3
4
5
6
7
8
s := []int{2, 3, 5, 7, 11, 13}

s = s[1:4] // [3 5 7]
s = s[:2] // [3 5]
s = s[:] // [3 5]
// 到這邊為止, 感覺 slice 的物件都是從上個 slice 物件建立 reference 來的
s = s[3:5] // [11 13]
//上面的 slice 長度感覺只有 2, 但是下面可以用 [3:5] 取到原有陣列的後面內容

Slice length and capacity

length: the number of elements it contains.
capacity: the number of elements in the underlying array, counting from the first element in the slice.

The length and capacity of a slice: len(s) and cap(s).

You can extend a slice’s length by re-slicing it, provided it has sufficient capacity.

Nil slices

The zero value of a slice is nil.
A nil slice has a length and capacity of 0 and has no underlying array.

Creating a slice with make

Slices can be created with the built-in make function;
this is how you create dynamically-sized arrays.

The make function allocates a zeroed array and returns a slice that refers to that array:

1
a := make([]int, 5)  // len(a)=5

To specify a capacity, pass a third argument to make:

1
b := make([]int, 0, 5) // len(b)=0, cap(b)=5

Slices of slices: multidimensional array

Slices can contain any type, including other slices.

1
2
3
4
5
board := [][]string{
[]string{},
[]string{},
[]string{}
}

Appending to a slice with append

1
func append(slice []Type, elems ...Type) []Type

作用:
returns the updated slice. > 要自己存起來

1
2
slice = append(slice, elem1, elem2)
slice = append(slice, anotherSlice...)

If the backing array of s is too small to fit all the given values a bigger array will be allocated.
The returned slice will point to the newly allocated array.

背後的機制可以參考這篇文章: Go Slices: usage and internals
基本上 append 自己實作也可以, 實作範例這篇文章也有講到

Q:檢查 slice 長度之後新建一個陣列, 把內容全部搬過去, 這個動作用 array 或者 slice 有何差異? 因為 slice 也不是真的可以動態變動長度

A: 用 slice 可以由 go 自動處理, 長度變更透過重新指定新的 slice 取代舊的 slice 來達成

As a special case, it is legal to append a string to a byte slice, like this:

1
slice = append([]byte("hello "), "world"...)

Range

for loop iterates over a slice or map.

Q: array 可以嗎? > 可

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.

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

If you only want the index, drop the , value entirely.

Map

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

var m map[string]Vertex

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

## Map literal
```go
m = map[string]Vertex{
"Bell Labs": Vertex{
40.68433, -74.39967,
},
"Google": Vertex{
37.42202, -122.08408,
},
}

Q: 看不懂: If the top-level type is just a type name, you can omit it from the elements of the literal.

1
2
3
4
m = map[string]Vertex{
"Bell Labs": {40.68433, -74.39967,},
"Google": {37.42202, -122.08408,},
}

Mutating Map

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// insert or update an element
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:
// 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 for the map's element type.
elem, ok = m[key]

// if elem, ok not declared, can use short declaration
elem, ok := m[key]

Function values (First class function)

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

Function 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.