【Go语言入门系列】前面的文章:算法
本文介绍Go语言的方法的使用。数据结构
若是你用过面向对象的语言,好比Java,那你确定对类、对象、成员变量、方法等很熟悉。app
简单地来讲,类是对一类事物的抽象,成员变量是该事物的属性,方法是该事物具备的行为,对象则是该事物所对应的具体个体。数据结构和算法
好比说,狗(类),名字(属性),叫(方法),哮天犬(对象)。函数
可是Go语言中并无类,天然也没有面向对象中的成员变量和成员方法。可是Go语言中有相似的概念——结构体,结构体中的字段能够看作类中成员属性。指针
Go中也有相似于面向对象中方法的概念,也叫方法(method
),这种方法实际上是一种特殊的函数(function
)——带有接收者(receiver
)的函数。code
方法的声明方式以下:对象
func (接受者) funcName(参数们) (返回值们)
能够看出方法的声明方式和函数的声明方式差很少,可是多了一个接收者,该接收者是一个结构体类型。下面是一个实例:get
package main import "fmt" type dog struct { name string } func (d dog) say() {//方法 fmt.Println(d.name + " 汪汪汪。。。方法") } func main() { d := dog{"哮天犬"} d.watchDoor() }
运行:string
哮天犬 汪汪汪。。。方法
say()
是一个方法,d
是接收者,是一个结构体类型参数,方法里能够访问接收者的字段:
fmt.Println(d.name + " 汪汪汪。。。方法")
经过.
能够调用方法:
d.say()
方法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
使方法在概念上属于结构体,就像结构体的字段同样,可是没有写在结构体内。
从这三个方法中能够看出:只要方法的接收者不一样,即便方法名相同,方法也不相同。
接收者可使用指针,和函数的参数使用指针同样(参考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语言基础开始介绍,适合从零开始的初学者。
欢迎关注,咱们一块儿踏上行程。
若有错误,还请指正。