Go語言允許使用者定義型別。當使用者聲明一個類型時,這個聲明就給編譯器提供了一個架構,告知必要的記憶體大小和資訊。
聲明結構類型
type user struct { name string email string}
上述代碼聲明的結構類型有2個欄位,每個欄位都基於一個內建類型。一旦聲明了類型,就可以使用這個類型建立值。
使用結構型別宣告變數
var zuckjet user
我們用關鍵字var建立了類型為user且名為zuckjet的變數。當聲明變數時,這個變數對應的值總是會被初始化。這個值要麼是用指定的值初始化,要麼用零值來初始化。對數值來類型來說,零值是0;對字串來說,零值是Null 字元串。
下面我們來看一下如何聲明一個user類型的變數,並使用某個非零值作為初始值。
zuckberg := user{ name: "zuckberg" email: "zuckjet@gmail.com"}
方法
方法能給使用者定義的類型添加新的行為。方法實際上也是函數,知識在聲明的時,在關鍵字func和方法名之間增加了一個參數。
func (u user) notify() { fmt.Printf(u.name)}
在上面的代碼中,關鍵字func和函數名之間的參數被稱作接收者,將函數與接收者的類型綁在一起。如果一個函數有接收者,這個函數就被稱為方法。下面我們來看一個簡單的demo:
package mainimport ( "fmt")type user struct { name string email string}func (u user) notify() { fmt.Println(u.name)}func main() { bill := user{"zuckjet", "zuckjet@gmail.com"} bill.notify()}// zuckjet
首先我們頂一個一個user類型,然後notify使用值接收者實現了一個方法,最後我們通過建立一個user類型的變數bill並調用notify方法。
當我們通過bill.notify()調用方法的時候,notify方法中的u變數的值就等同於變數bill。為什麼我說等同於變數bill呢?因為
使用值接收者聲明方法,調用時會使用這個值的一個副本來執行。
我們稍微修改一下上面的代碼即可驗證:
package mainimport ( "fmt")type user struct { name string email string}func (u user) notify() { u.name = "zuckberg" fmt.Println(u.name)}func main() { bill := user{"zuckjet", "zuckjet@gmail.com"} bill.notify() fmt.Println(bill.name)}// zuckberg// zuckjet
因為變數u是bill的一個副本,所以改變它裡面屬性的值,是不會影響bill本身的值的。
值得注意的是,在Go語言中我們還可以使用指標來調用值接收者聲明的方法,儘管這看起來似乎不太合理。
我們看一下下面的代碼:
package mainimport ( "fmt")type user struct { name string email string}func (u user) notify() { fmt.Println(u.name)}func main() { bill := &user{"zuckjet", "zuckjet@gmail.com"} bill.notify()}// zuckjet
這次我們定義的變數bill是指標類型的,用指標類型的變數來調用noify方法的時候,依然能夠輸出bill的name屬性值。看到這裡或許你有些疑惑,不是說方法notify中的變數u就等同於變數bill嗎,為啥bill是一個指標類型的時候還能夠正確輸出name屬性值呢。其實,我們可以認為Go在背後替我們做了如下操作:
(*bill).notify()
上面我們講述的是使用值接受者聲明方法,除此之外我們還可以使用指標接收者聲明方法。我們來看下面的代碼:
package mainimport ( "fmt")type user struct { name string email string}func (u *user) notify() { fmt.Println(u.name)}func main() { bill := user{"zuckjet", "zuckjet@gmail.com"} bill.notify()}// zuckjet
同樣在調用notify方法時,Go在背後做了這樣一件事情:
(&bill).notify()
當把上面的notify()方法改造為:
func (u *user) notify() { fmt.Println(u.name) fmt.Println(&u) fmt.Println(*u) fmt.Println(u)}// 輸出結果zuckjet0xc420088018{zuckjet zuckjet@gmail.com}&{zuckjet zuckjet@gmail.com}