GO學習筆記 物件導向程式設計之方法(16)

2021-08-30 08:34:43 字數 2986 閱讀 3890

講完了結構體,如果要為這個結構體物件設計一些實用的方法,比如對於單鏈表,有單鏈表的遍歷和反轉等,這些方法是如何來定義的呢?

c++中,這些方法也一同放在class中定義了,但是go中不可以,必須在結構體外定義。因此,為了能夠對結構體進行上述實用的操作,go中有了方法這個概念。

方法本質其實就是乙個函式,下面來看看實現細節。

方法的定義

//定義乙個單鏈表的節點

type listnode struct

//定義乙個方法來遍歷這個單鏈表

func (node *listnode) printlist()

node = node.next }}

func main()

root.next = &listnode

root.next.next = &listnode

root.next.next.next = &listnode

root.printlist() //使用該方法

}

輸出結果

1->2->3->4
我們可以看到,方法的定義和普通函式的定義差不多,也就多了乙個(node *listnode),這其實就是乙個接收器,表示我們這個方法的接收器型別是 *listnode,這樣,這個方法就可以在這個接收器型別內部被訪問了(使用.訪問)

其實函式和方法差不了很多,可以看下面

func (node *listnode) printlist()

node = node.next }}

func printlist(node *listnode)

node = node.next

}}

上面是方法,下面是函式,兩者只是呼叫的方式不同罷了。那麼為什麼還要方法?

先來看一下值接收器

//定義乙個單鏈表的節點

type listnode struct

//定義乙個方法改變node的val,這裡是值接收器

func (node listnode) setvalue(val int)

func (node listnode) print()

func main() //這裡root是乙個指標物件

root.setvalue(2)

root.print()

}

上面的setvalue的接收器型別是乙個listnode,因為go中的函式都是值傳遞,所以在這裡也是值傳遞。但是在外面,方法的呼叫者root確是乙個指標,也就是說呼叫者其實是乙個*listnode,而不是listnode。但是在這裡還是呼叫成功的,編譯器會進行自動轉化,在接收的時候它其實拿到的是root指向的內容,而不是root這個位址。

1
但是因為是值接收器,所以這邊對這個值進行改變,不會改變原來的root。

再來看下指標接收器

//定義乙個單鏈表的節點

type listnode struct

//定義乙個方法改變node的val,這裡是指標接收器

func (node *listnode) setvalue(val int)

func (node listnode) print()

func main() //這裡root是乙個listnode物件

root.setvalue(2)

root.print()

}

可以看到,我們將 setvalue 方法的接收器改為了指標接收器,但是我們將root改為了乙個listnode的物件,而不是它的指標。但是其實這裡還是會呼叫成功的,編譯器會自動將其轉化為指標接收。

2
這裡就將原來root中的值給改變了,這就是值接收器與指標接收器的區別,關鍵在於可不可以改變原有變數的值。

總結一下,值接收器和指標接收器都可以接受值和指標傳遞。

那麼兩者何時使用呢?

go中的nil不像c++中的null,null是乙個雷區,乙個指標一旦是null,那麼對它進行操作都將變為非法的。但是go不一樣,這一點在之後的學習中應該還會感覺到。

//定義乙個單鏈表的節點

type listnode struct

//定義乙個方法改變node的val,這裡是指標接收器

func (node *listnode) setvalue(val int)

node.val = val

}func main()

輸出結果

ignore
所以對於乙個nil指標,我們還是可以對它呼叫方法。

接收器還可以不是結構體型別的,還可以是別的型別。但是有乙個前提,為了在乙個型別上定義乙個方法,方法的接收器型別定義和方法的定義應該在同乙個包中。

比如,我們想將int設為接收器型別

func (num1 int) add(num2 int) int

func main()

程式會報錯,因為add方法的定義和int方法的定義不在乙個包中。

cannot define new methods on non-local type int
我們可以使用型別別名來解決下面的問題。

//定義乙個新型別myint,其實也就是int

type myint int

func (num1 myint) add(num2 myint) myint

func main()

輸出結果

3
所以,通過這種方式,可以對普通的型別實現方法。

Go 物件導向程式設計之繼承

package main import fmt 編寫乙個學生考試系統 小學生 type pupil struct 顯示他的成績 func p pupil showinfo func p pupil setscore score int func p pupil testing 大學生,研究生。大學生...

Go之物件導向程式設計之繼承

golang的繼承與j a和php不太一樣,如php繼承需要用到extends關鍵字,而golang使用的是匿名繼承或有名繼承。二 簡單舉例 package main import fmt type brand struct type goods struct func main 結果 go run...

Go 物件導向程式設計

值語義與引用語義的區別在於賦值。值型別不會改變變數值,引用型別會改變變數值。go 語言中大多數型別都是基於值語義,包括 基本型別 如byte int bool float32 float64和string 復合型別 如陣列 array 結構體 struct 和指標 pointer 等。go語言中的陣...