【Go語言入門系列】前面的文章:
- 【Go語言入門系列】(四)之map的使用
- 【Go語言入門系列】(五)之指標和結構體的使用
- 【Go語言入門系列】(六)之再探函式
本文介紹Go語言的方法的使用,
1. 宣告
如果你用過面向物件的語言,比如Java,那你肯定對類、物件、成員變數、方法等很熟悉,
簡單地來說,類是對一類事物的抽象,成員變數是該事物的屬性,方法是該事物具有的行為,物件則是該事物所對應的具體個體,
比如說,狗(類),名字(屬性),叫(方法),哮天犬(物件),
但是Go語言中并沒有類,自然也沒有面向物件中的成員變數和成員方法,但是Go語言中有類似的概念——結構體,結構體中的欄位可以看做類中成員屬性,
Go中也有類似于面向物件中方法的概念,也叫方法(method),這種方法其實是一種特殊的函式(function)——帶有接收者(receiver)的函式,
方法的宣告方式如下:
func (接受者) funcName(引數們) (回傳值們)
可以看出方法的宣告方式和函式的宣告方式差不多,但是多了一個接收者,該接收者是一個結構體型別,下面是一個實體:
package main
import "fmt"
type dog struct {
name string
}
func (d dog) say() {//方法
fmt.Println(d.name + " 汪汪汪,,,方法")
}
func main() {
d := dog{"哮天犬"}
d.watchDoor()
}
運行:
哮天犬 汪汪汪,,,方法
say()是一個方法,d是接收者,是一個結構體型別引數,方法里可以訪問接收者的欄位:
fmt.Println(d.name + " 汪汪汪,,,方法")
通過.可以呼叫方法:
d.say()
2. 方法和函式
方法method是具有接收者receiver的特殊函式function,下面的例子展示了method和function之間的區別,
package main
import "fmt"
type dog struct {
name string
}
func (d dog) say() {
fmt.Println(d.name + " 汪汪汪,,,方法")
}
func say(d dog) {
fmt.Println(d.name + " 汪汪汪,,,函式")
}
func main() {
d := dog{"哮天犬"}
d.watchDoor()
watchDoor(d)
}
運行:
哮天犬 汪汪汪,,,方法
哮天犬 汪汪汪,,,函式
你可能會問,在這個例子中,既然方法和函式的運行結果一樣,那使用方法豈不是多此一舉,為何不繼續使用函式?
換一個場景:現在有狗、貓、兔子等動物,他們都會叫,只是叫聲不同:
package main
import "fmt"
type dog struct {
name string
}
type cat struct {
name string
}
type rabbit struct {
name string
}
func dogSay(d dog) {
fmt.Println(d.name + " 汪汪汪,,,函式")
}
func catSay(c cat) {
fmt.Println(c.name + " 喵喵喵,,,函式")
}
func rabbitSay(r rabbit) {
fmt.Println(r.name + " 吱吱吱,,,函式")
}
func main() {
d := dog{"哮天犬"}
c := cat{"加菲貓"}
r := rabbit{"玉兔"}
dogSay(d)
catSay(c)
rabbitSay(r)
}
運行:
哮天犬 汪汪汪,,,函式
加菲貓 喵喵喵,,,函式
玉兔 吱吱吱,,,函式
上面的三個函式有什么不妥之處呢?
首先,這三個函式都是用來表示叫這一行為,一般來說函式名都會叫say(),但因為不同的動物,函式名不能相同,為了做區別而做出了改變,
其次,叫這個行為應該屬于動物,二者在概念上不能分開,比如,說話這個行為是每個人都具有的,但是說話并不能離開人而獨自存在,
此時,方法method的優點就體現了出來:
package main
import "fmt"
type dog struct {
name string
}
type cat struct {
name string
}
type rabbit struct {
name string
}
func (d dog) say() {
fmt.Println(d.name + " 汪汪汪,,,方法")
}
func (c cat) say() {
fmt.Println(c.name + " 喵喵喵,,,方法")
}
func (r rabbit) say() {
fmt.Println(r.name + " 吱吱吱,,,方法")
}
func main() {
d := dog{"哮天犬"}
c := cat{"加菲貓"}
r := rabbit{"玉兔"}
d.say() //呼叫
c.say()
r.say()
}
運行:
哮天犬 汪汪汪,,,方法
加菲貓 喵喵喵,,,方法
玉兔 吱吱吱,,,方法
三個方法的方法名都一樣,每個方法都有一個接受者receiver,這個receiver使方法在概念上屬于結構體,就像結構體的欄位一樣,但是沒有寫在結構體內,
從這三個方法中可以看出:只要方法的接收者不同,即使方法名相同,方法也不相同,
3. 指標和接收者
接收者可以使用指標,和函式的引數使用指標一樣(參考Go語言入門系列(六)之再探函式),接收者使用指標傳的是參考,不使用指標傳的是值拷貝,看下面一個例子:
package main
import "fmt"
type dog struct {
name string
}
func (d *dog) rename(name string) {
d.name = name
fmt.Println("方法內:" + d.name)
}
func (d dog) rename1(name string) {
d.name = name
fmt.Println("方法內:" + d.name)
}
rename和rename1都是改變名字的方法,一個傳參考,一個傳值,只有rename能真正改變名字,
func main() {
d := dog{"哮天犬"}
d.rename("小黑黑")
fmt.Println(d.name)
}
運行:
方法內:小黑黑
小黑黑
rename把“哮天犬”改為了“小黑黑”,
func main() {
d := dog{"哮天犬"}
d.rename1("小紅紅")
fmt.Println(d.name)
}
運行:
方法內:小紅紅
哮天犬
rename1只在方法內改變了名字,并沒有真正改變“哮天犬”,因為rename1接收的是d的一個拷貝,
方法的指標接收者可以進行重定向,什么意思呢?下面用四段代碼來說明,
如果函式的引數是一個指標引數,那么該函式就必須接收一個指標才行,如果是值則報錯:
package main
import "fmt"
func double(x *int) {
*x = *x * 2
}
func main() {
i := 2
double(&i) //編譯正確
double(i) //報錯
fmt.Println(i)
}
而如果方法的接收者是一個指標,那么該方法被呼叫時,接收者既可以是指標,又可以是值:
package main
import "fmt"
func (d *dog) rename(name string) {
d.name = name
fmt.Println("方法內:" + d.name)
}
func main() {
d := dog{"哮天犬"}
d.rename("小黑黑") //接收者是值,編譯正確
//(&d).rename("小黑黑") //接收者是指標,編譯正確
fmt.Println(d.name)
}
對于指標接收者來說,d.rename("小黑黑")被解釋為(&d).rename("小黑黑"),如此一來,我們就不需要在意呼叫方法的接收者是否為指標型別,因為Go會進行“重定向”,
同理,反過來也可以,
如果函式的引數是值,而不是指標,那么該函式必須接受值,否則會報錯:
package main
import "fmt"
func double(x int) {
x = x * 2
}
func main() {
i := 2
p := &i
double(*p) //引數是值,編譯正確
//double(p) //引數是指標,報錯
fmt.Println(i)
}
而如果方法的接收者是一個值,那么該方法被呼叫時,接收者既可以是值,又可以是指標:
package main
import "fmt"
func (d dog) rename1(name string) {
d.name = name
fmt.Println("方法內:" + d.name)
}
func main() {
d := dog{"哮天犬"}
p := &d
p.rename1("小紅紅") //接收者是指標,編譯正確
//(*p).rename1("小紅紅") //接收者是值,編譯正確
fmt.Println(d.name)
}
對于值接收者來說,p.rename1("小紅紅")被解釋為(*p).rename1("小紅紅"),如此一來,我們就不需要在意呼叫方法的接收者是否為值,因為Go會進行“重定向”,
作者簡介
我是行小觀,我會在公眾號『行人觀學』中持續更新Java、Go、資料結構和演算法、計算機基礎等相關文章,
本文章屬于系列文章「Go語言入門系列」,本系列從Go語言基礎開始介紹,適合從零開始的初學者,
歡迎關注,我們一起踏上行程,
如有錯誤,還請指正,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/332.html
標籤:Go
