Go 起手式之二


指標

在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

筆記參考

Larry Lu 的2019 iT 邦幫忙鐵人賽
官方文件

#Go Pointer #Go Slice #Go Struct #Go Map #Go Range
逼自己寫點筆記;體驗重新學習的感覺,不只是另一個語言,而是帶著過去的更豐富的經驗,有更多角度與體會地去探索另一個新的生態系;希望幫助自己也可能幫助別人;很喜歡Gopher好想買一隻放在書桌或床頭上(被圈粉。






Related Posts

Vue.js 學習旅程Mile 9 – Event Handling 事件處理篇-1:methods & v-on

Vue.js 學習旅程Mile 9 – Event Handling 事件處理篇-1:methods & v-on

yuhantaiwan
OpenCV在空拍影像中單一辨識顏色

OpenCV在空拍影像中單一辨識顏色

zavke
Day 02 任務

Day 02 任務

CaeserNieh


Comments