指標
在Go的世界中,指標意思是存取一個值在記憶的位置。
- & 取得變數記憶體位置
- * 透過記憶體位置取得變數值
func main() {
i, j := 42, 2701
// 取值的方法
p := &i // &i 表示 p 得到了 i 在記憶體中的位置
fmt.Println(*p) // *p 表示 透過 p 所記錄的記憶體位置,幫我拿到 i 的值,印出 42
// 存值的方法
*p = 21 // 透過 p 所記錄的記憶體位置,我給定一個新的值
fmt.Println(i) // 印出 21
p = &j // &j 表示 p 得到了 j 在記憶體中的位置
*p = *p / 37 // 拿 j 的值除以 37 並將這個新的值指給 j
fmt.Println(j) // 印出 73
}
資料結構
Array
在Go的世界中,如果想對陣列的size做規範可以採用array
// array的宣告,給定一個size
var a [2]string
a[0] = "Hello"
a[1] = "World"
a[2] = "!" // error 超出size
// 初始化陣列
b := [6]int{2, 3, 5, 7, 11, 13}
Slice
在Go的世界中,如果對陣列的大小希望保持彈性就採用slice。
// 只要不給定一個size,就是告訴 Go 這是一個 slice 的宣告
s := []int{2, 3, 5, 7, 11, 13}
// 沒有初始化就是 nil
var s []int // 是 nil不是 0 喔!!
len(s) // 長度才是 0
cap(s) // 容量也是 0
在Go的世界中,array和slice都具有length和capacity的屬性,不一樣的是array是固定的,無法被切割(run)
- length就是slice裡現有元素的數量
- capacity對應到slice原有的元素的數量
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
func main() {
s := []int{2, 3, 5, 7, 11, 13}
printSlice(s) // len=6 cap=6 [2 3 5 7 11 13]
// 切割這個 slice 使它的 length 為零
s = s[:0]
printSlice(s) // len=0 cap=6 []
// 擴張這個 slice 使它的 length 為 4
s = s[:4]
printSlice(s) // len=4 cap=6 [2 3 5 7]
// 移除掉前兩個元素,改變原來的容量
s = s[2:]
printSlice(s) // len=2 cap=4 [5 7]
}
擴充slice的長度和裁減範圍
s := []int{0, 1, 2, 3}
fmt.Println(s) // [0 1 2 3]
// 增加長度
s = append(s, 4, 5)
fmt.Println(s) // [0, 1, 2, 3, 4, 5]
// 也可將它裁切
fmt.Println(arr[1:4]) // [1, 2, 3]
fmt.Println(arr[1:]) // [1, 2, 3, 4, 5]
struct
設計一個可以複用的結構(stuct)來開發
// 宣告一個 struct
type Rectangle struct {
H int
W int
}
// 宣告一個 method
func (r Rectangle) Area() int {
return r.H * r.W
}
func main() {
rec := Rectangle{H: 10, W: 5}
// rec := Rectangle{10, 5} 也可以註明 H 和 W
fmt.Println(rec.Area()) // 10 x 5 = 50
rec.W = 10
fmt.Println(rec.Area()) // 10 x 10 = 100
}
(補充)結構指標
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
p := &v // 讓 p 取得 v 的記憶體位置
p.X = 6 // (*p).X = 6 也是可以,但不必這麼做
fmt.Println(v) // 印出 {6 2}
}
Map
Map 是一個鍵值配對(key/value)的結構。鍵是唯一的,而值可以重複。
宣告方式
// 宣告一個變數是 map 它包含一個鍵(String)一個值(int)
var x map[string]int // 未初始化,所以會產生一個 nil map,也就是沒有任何 key
// 初始化宣告,給定一個key和value
var x = map[string]int{"apple": 1}
// 短宣告,給定一個key和value
x := map[string]int{"apple": 1}
// 初始化多組 key/value
elements := map[string]string{
"H": "Hydrogen",
"He": "Helium",
"Li": "Lithium",
"Be": "Beryllium",
"B": "Boron",
"C": "Carbon",
"N": "Nitrogen",
"O": "Oxygen",
"F": "Fluorine",
"Ne": "Neon",
}
賦予值的方式
// Example1: 新增一個鍵與值
x["apple"] = 1
x["banana"] = 5
fmt.Println(x) // 印出 map[apple:1 banana:5]
fmt.Println(x["banana"]) // 印出 5
// Example2: 刪除某個鍵
delete(x,"banana") // (map, key name)
// Example3: 查詢map的長度
len(x)
印出不存在的鍵
通常在編譯的時候會報錯,但執行中(go run)的 Map 不會,而是丟出空值。
name, ok := elements["Al"]
fmt.Println(name, ok) // 印出 空值 false
// 修正後
if name, ok := elements["Al"]; ok {
fmt.Println(name, ok)
}
設計一個 Nested Map
elements := map[string]map[string]string{
"H": map[string]string{
"name":"Hydrogen",
"state":"gas",
},
"He": map[string]string{
"name":"Helium",
"state":"gas",
},
"Li": map[string]string{
"name":"Lithium",
"state":"solid",
},
"Be": map[string]string{
"name":"Beryllium",
"state":"solid",
},
"B": map[string]string{
"name":"Boron",
"state":"solid",
},
"C": map[string]string{
"name":"Carbon",
"state":"solid",
},
"N": map[string]string{
"name":"Nitrogen",
"state":"gas",
},
"O": map[string]string{
"name":"Oxygen",
"state":"gas",
},
"F": map[string]string{
"name":"Fluorine",
"state":"gas",
},
"Ne": map[string]string{
"name":"Neon",
"state":"gas",
},
}
if el, ok := elements["Li"]; ok {
fmt.Println(el["name"], el["state"])
}
range
當有了array或slice或map這種集合資料的結構,我們可能需要從這些集合中找到某一個值或列出所有的值,因此,我們可以給定一個range來代表這些集合
numbers := [4]int{1, 2, 3}
for i,x:= range numbers {
fmt.Printf("第 %d 位 x 的值 = %d\n", i, x)
}
// 第 0 位 x 的值 = 1
// 第 1 位 x 的值 = 2
// 第 2 位 x 的值 = 3
// 第 3 位 x 的值 = 0
m := map[string]int{
"one": 1,
"two": 2,
}
for k, v := range m {
fmt.Printf("%s -> %d\n", k, v)
}
// one -> 1
// two -> 2