方法是什么
- Go方法是作用在接受者(个人理解成作用对象)上的一个函数,接受者是某种类型的变量,因此方法是一种特殊类型的函数。
- 接收者可以是任何类型,不仅仅是结构体,Go中的基本类型(int,string,bool等)也是可以,或者说数组的别名类型,甚至可以是函数类型。但是,接受者不能是一个接口类型,因为接口是一个抽象的定义,方法是一个具体实现。
- 一个类型加上它的方法等价于面向对象中的一个类。一个重要的区别是:在 Go 中,类型的代码和绑定在它上面的方法的代码可以不放置在一起,它们可以存在在不同的源文件,唯一的要求是:它们必须是同一个包的。
- 类型 T(或 *T)上的所有方法的集合叫做类型 T(或 *T)的方法集。
- 因为方法是函数,所以同样的,不允许方法重载,即对于一个类型只能有一个给定名称的方法。但是如果基于接收者类型,是有重载的:具有同样名字的方法可以在 2 个或多个不同的接收者类型上存在,比如在同一个包里这么做是允许的
- 别名类型不能有它原始类型上已经定义过的方法(因为别名类型和原始类型底层是一样的)。
定义方法的格式
1 func(recv recevier_type)methodName(parameter_list)(return_value_list){}
方法名之前,func关键字之后的括号中指定接受者(receiver)。
如果recv是接受者(receiver)的实例,Method1是recv的方法名,那么方法的调用遵循传统的object.name选择器符号:recv.Method1()。假如recv是一个指针,Go会自动解引用。
1 package main 2 3 import "fmt" 4 5 type TwoInts struct { 6 a int 7 b int 8 } 9 func(ti *TwoInts)Add()int{ 10 return ti.a + ti.b 11 } 12 13 func(ti *TwoInts)Plus()(re int){ 14 re = ti.a * ti.b 15 return 16 } 17 18 func(ti *TwoInts)AddOther(param int)(re int){ 19 re = ti.a + ti.b +param 20 return 21 } 22 // 结构体上的例子 23 func main(){ 24 tt := new(TwoInts) 25 tt.a = 10 26 tt.b = 20 27 28 fmt.Println(tt.Add()) 29 fmt.Println(tt.Plus()) 30 31 ttt := TwoInts{3,5} 32 fmt.Println(ttt.AddOther(7)) 33 }
package main import "fmt" type IntVetor []int func (iv IntVetor) Sum(param int) (re int) { su := 0 for _, v := range iv { su = su + v } re = su + param return } // 非结构体上的例子 func main() { tv := IntVetor{3,4,5} fmt.Println(tv.Sum(333)) }
如果想给基本类型添加方法,一般是行不通的,因为基本类型和你添加方法的包不是同一个,会出现编译错误。
方法和函数的区别
- 方法只能被其接受者调用
- 接收者是指针时,方法可以改变接受者的值(或状态),函数也能做到
- 接受者和方法必须在同一个包内
方法的接受者是值或者指针的区别
- 当接受者是一个值的时候,这个值是该类型实例的拷贝
- 如果想要方法改变接受者的数据,就在接受者的指针类型上定义该方法。否则,就在普通的值类型上定义方法。
总结:指针方法和值方法都可以在指针或者非指针上被调用。也就是说,方法接收者是指针类型时,指针类型的值也是调用这个方法,反之亦然。
内嵌类型的方法和继承
当一个匿名类型被内嵌在结构体中时,匿名类型的可见方法也同样被内嵌,这在效果上等同于外层类型继承了这些方法,将父类型放在子类型中实现(子类型中的方法,可以直接使用父类型加点子类型方法的方式调用[father.childMethod()])
但是当父类型和子类类型有相同名字的方法怎么办呢?父类型的方法会覆盖子类型的。
1 package main 2 3 import "fmt" 4 5 type Child struct { 6 a, b int 7 Father// 【重点】这里必须是匿名类型才可以实现继承的效果,否则不可以!!!!!! 8 } 9 type Father struct { 10 name string 11 } 12 13 func (fa *Father) GetName() (re string) { 14 re = chi.name 15 return 16 } 17 18 func main() { 19 c := Child{1, 3, Father{"Kobe"}} 20 fmt.Println(c.GetName()) 21 }