Go編程基礎——方法method

方法method
1、Go 中 雖 沒 有 class , 但 依 舊 有 method
2、通 過 顯 示 說 明 receiver 來 實 現 與 某 個 類 型 的 組 合
3、只 能 爲 同 一 個 包 中 的 類 型 定 義 方 法
4、Receiver 可 以 是 類 型 的 值 或 者 指 針
5、不 存 在 方 法 重 載
6、 可 以 使 值 或 指 針 來 調 用 方 法, 編 譯 器 會 自 動 完成轉換
7、從 某 種 意 義 上 來 說 , 方 法 是 函 數 的 浯 法 糖 , 因 爲 receiver 其 實 就 是
方 法 所 接 收 的 第 1 個 參 數 ( Method Value vs. Method Expression )
8、如 果 外 部 結 構 和 嵌 入 結 構 存 在 同 名 方 法 , 則 優 先 調 用 外 部 結構的 方 法
9、類 型 別 名 不 會 擁 有 底 層 類 型 所附帶 的 方 法
10、 方 法 可 以 調 用 結 構 中 的 非 公 開 字 段

首先思考如何爲一個函數寫方法method,是通過receiver。根據接收者的類型來判斷方法是來自哪個結構體

type Aa struct{
   name string
}
type Bb struct{
   name string
}

func main() {
a:=Aa{}
a.print()
a.sayHello("China")
}
func (a Aa)print(){
   fmt.Println("Aa")
}
func (b Aa)sayHello(w string)  {
   fmt.Println(w)
}

運行結果

Aa
China

首先來看方法print,局部變量a的接受者Aa,方法的名稱是print。在main方法中首先聲明一個結構a,這就可以使用接受者來判斷這個結構體有哪些方法,這裏是有print方法在結構體Aa中。通過接收者類型Aa就這樣把結構體Aa和方法print鏈接在一起。
Go語言中不存在方法的重載,是指同一個類型的結構體,不同的結構體存在相同的方法名是允許的。看如下程序:

func (a Aa)print(){
   fmt.Println("Aa")
}
func(a Aa)print(i int){
   fmt.Println("Aa in override")
}

這樣編譯器會報錯,這裏的print()和print(i int)的接收者都是Aa結構體,所以這樣就構成了方法的重載,這是在Go語言中沒有實現的底層機制,換句話說就是不允許方法重載。

method redeclared 'Aa.print' less... (Ctrl+F1)
Reports names redeclared in this block.

但是不同的結構體方法名相同是可以的。

type Aa struct{
   name string
}
type Bb struct{
   name string
}

func main() {
a:=Aa{}
a.print()
b:=Bb{}
b.print()
}
func (a Aa)print(){
   fmt.Println("Aa")
}
func (b Bb)print(){
   fmt.Println("Bb")
}

運行結果

Aa
Bb

接收者不一樣,方法名相同不算構成方法重載,這是允許的

這裏的接收者是作爲第一個參數傳遞,就要搞清楚是值傳遞還是指針傳遞這個問題。

type Aa struct{
   name string
}
type Bb struct{
   name string
}

func main() {
a:=Aa{}
a.print()
fmt.Println(a.name)
b:=Bb{}
b.print()
fmt.Println(b.name)
}
func (a *Aa)print(){
   a.name="AAA"
   fmt.Println("Aa")
}
func (b Bb)print(){
   b.name="BBB"
   fmt.Println("Bb")
}

運行結果

Aa
AAA
Bb

首先第一個print()使用的是指針傳遞,第二個print()使用的不帶指針的傳遞,從結果可以看出接收者也是服從一般的參數傳遞規則的,指針傳遞就會改變原來內存地址對應的值,值傳遞則不會改變變量的值。這裏也可以看出Go語言是通過自動判斷使用的指針傳遞還是值傳遞,有程序爲例,前邊

func (a Aa)print(){
   fmt.Println("Aa")
}

和後邊的

func (a *Aa)print(){
   a.name="AAA"
   fmt.Println("Aa")
}

相比,後邊的傳遞是指針傳遞,但最後兩種的調用都是一樣的使用

a:=Aa{}
a.print()

Go語言底層自動識別和判斷。
接下來是類型別名和方法的組合的應用

type TZ int
func main() {
var a TZ
a.print()
}
func (a *TZ)print(){
   fmt.Println("func of TZ")
}

運行結果

func of TZ

這樣通過type實現一個方法的綁定,這樣的int對應的TZ只能在這個包內找到對應的方法。
Method Value vs. Method Expression
看如下程序

type TZ int
func main() {
var a TZ
a.print()
(*TZ).print(&a)
}
func (a *TZ)print(){
   fmt.Println("func of TZ")
}

運行結果

func of TZ
func of TZ

注意到對於(*TZ)來說,a代表的是指針,這裏就需要取它的地址符號才能獲取值,這也是Method Value和Method Expression表達上的不同,結果是一樣的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章