Go 的 Map、Struct、Interface 與 Error 處理

Go 特色

  • 執行效能很好
  • 每個變數型態在編譯時期就完全決定(statically typed)
  • 自動 compile 成為 native 程式碼
  • Interfaces
  • Functions 可以回傳多重的值
  • 內建 concurrency 機制:Goroutines and Channels

Map

宣告 Map

var m map[string]int  

Map 的型態是一種 reference ,所以上面範例中 m 的值是 nil,若嘗試寫入空的 map 會造成 runtime panic。

建立 Map

m = make(map[string]int)  

或下面這種方式亦可:

m = map[string]int{}  

操作 Map

將 Key uid 對應的值設定成為 5:

m["uid"] = 5  

uid 的值取出並指定給新的變數 i:

i := m["uid"]  

注意當傳入 Key 的值不存在時,預設回傳值是 0:

j := m["notexist"]  
// j == 0

取出 Key 的值(下面例子是 i)時順便確認該 Key 是否已經存在,若 Key 存在於 map 當中 ok 的值是 true,反之則為 false:

i, ok := m["uid"]  

查看 Map 裡面 items 的數量:

n := len(m)  

uid 對應的 item 從 map 裡面移除:

delete(m, "uid")  

Structs

Go 裡面沒有 Classes,只有 Structs,但 Structs 可以有 functions

宣告 Struct:

type User struct {  
    Name string  // name of the user
    Value int    // user's value
}

操作 Struct:

var u = User{"Alice", 5}  
var u = User{Name: "Alice", Value: 5} // 透過指定 Key 的值來建立一個 struct  
var u = []User{{"Alice", 5},{"Bob", 1}} // 初始出一個 structs 的陣列

u.Value = 100  

為 Struct 加上 methods:

func (u User) getValue() int {  
    return u.Value
}

注意上面的方法每次 method 被呼叫的時候,struct 都會被整份複製一次,因此若要透過 method 改變 struct 的值必須使用下面的方法:

func (u *User) add(n int) {  
    u.Value += n
}

Pointers

p := User{"Alice", 5}  // p 是個 User  
q := &p            // q 是指到 User 的 Pointer  

Interface

宣告 Interface:

type Greeting interface {  
    Hello() string
}

不需要在 type 中宣告 implement 某個 interface,假如 interface 中的 functions 都有被對應到,自動滿足成為該 interface 的一員:

type Foo struct {}

func (foo Foo) Hello() string {  
    return "Hello!"
}

Errors

GoLang 沒有 exception handling,function 多一個型態為 Error 的回傳值就可以在執行時檢查是否有錯誤:

func getValue() (int, error) {  
}

func main() {  
    result, error := getValue()
    if (error != nil) {
        // 處理遇到的錯誤
    } else {
        // 沒有錯誤
    }
}

而 Error 是一個內建的 interface:

type error interface {  
    Error() string
}

操作 Error

var err error = errors.New("A new error")  
fmt.Println(err.Error())  // A new error  

或透過 Errorf 處理錯誤訊息:

err = fmt.Errorf("%s", "test error for fmt.Errorf")  
fmt.Println(err.Error())  

定義客製化型態的 Error:

type CustomError struct {  
    Path string
    Err error
}

func (c *CustomError) Error() string {  
    return e.Path + ": " + e.Err.Error()
}

相關參考