Go 语言中 的方法 ( Method ) 是一种作用 于特定类型变量 的函数 。这种特定类型变量 叫做接收器( Receiver ) 。 如果将特定类型理解为结构体或“类”时,接收器的概念就类似于其他语言中的 this 或 者 self。 在 Go 语言中,接收器的类型可以是任何类型,不仅仅是结构体,任何类型都可以拥有方法。
简单的说,我们可以给任何类型(包含内置类型)添加方法方法必须和特定的数据类型绑定才能使用,也就是说方法一定会有一个自己的接收器,接收器就是指定的数据类型,或者也可以称为一个实例方法和函数的区别是,函数没有作用对象,即不需要和特定的数据类型变量绑定.接收器变量 : ** 可以是任意的正确的变量名,可以命名为this,self 这样的命名,但是通常不建议这样做**,推荐的做法是 接收器类型 首字母的小写
**接收类型 : ** 接收器类型可以是指针类型也可以是非指针类型,可以是结构体,也可以是其他类型
方法名,参数列表,返回值列表和函数一致
(接收器变量 接收器类型) 总称为 接收器 Receiver 根据接收器类型 可以分为 指针接收器和非指针接收器 两种接收器会在具体执行中会有不同的效果,这种不同的效果最基本的体现是值传递的影响和引用传递的影响
func (接收器变量 接收器类型) MethodName(参数列表) (返回值列表){ }任何类型都可以有方法
我们以Go语言内置类型 int 为例
package main import "fmt" // 定义一个新类型numA 但是其本质是int类型 type numA int // 给numA类型绑定了一个方法 getDouble func (a numA) getDouble(n int) (res1 int,res2 numA){ // 但是在内部编译的时候依然认为 numA类型和int类型不匹配,需要转换 // numA类型转换成int类型 res1 = int(a)*n // int类型转换成numA类型 res2 = a*numA(n) return } // 给numA类型绑定了一个方法 compare func (a numA) compare(n numA) numA{ if a > n { return a }else{ return n } } func main() { var AA numA = 9 // numA的类型变量调用绑定的方法 res,res1:= AA.getDouble(2) fmt.Println(res,res1) res2 := AA.compare(99) fmt.Println(res2) }go run main.go
18 18 99方法更多的时候是和结构体一起,构成面向对象编程
package main import "fmt" type Person struct { name string birth string hobby []string } func NewPerson(name string,birth string ,hobby []string) *Person{ return &Person{ name:name, birth:birth, hobby:hobby, } } // Person类型绑定的方法 func (p Person) SelfIntroduction(){ hobbys := "" for _,h := range p.hobby{ hobbys = hobbys+h+" " } fmt.Printf("大家好我叫 %s 我出生于 %s 我的爱好是 %s\n",p.name,p.birth,hobbys) } // Person类型绑定的方法不同的是接收器是指针类型的Person类型,引用传递 // 此处的是指针接收器,对原值有影响 func (p *Person) addHobby(h string){ p.hobby = append(p.hobby,h) } func main() { // 初始化一个person类型的实例 p1 p1 := NewPerson("Tom","1990.1.1",[]string{"足球"}) // 调用方法 p1.SelfIntroduction() p1.addHobby("篮球") p1.SelfIntroduction() // 初始化一个结构体变量 p2 (换一种说法) // p1 和 p2 在内存中有相同的布局,但是本质上是两个内存空间,毫不相关 p2 := NewPerson("Anne","1992.1.1",[]string{"看书","购物"}) p2.SelfIntroduction() }go run main.go
大家好我叫 Tom 我出生于 1990.1.1 我的爱好是 足球 大家好我叫 Tom 我出生于 1990.1.1 我的爱好是 足球 篮球 大家好我叫 Anne 我出生于 1992.1.1 我的爱好是 看书 购物由于指针的特性,修改指针接收器的任意成员,在方法调用结束之后,会对原有的数据产生效果
而非指针接收器是值拷贝一份,方法内修改接收器的成员,在方法结束之后不影响原有值
数据量小的对象赋值比较快,使用非指针接收器也合适,数据量大的对象赋值起来性能较低,使用指针接收器比较合适, package main import ( "fmt" ) type Point struct { x int y int } // 指针接收器 func (p *Point) forwardTo(x1, y1 int) { p.x += x1 p.y += y1 } // 非指针接收器 func (p Point) retreatTo(x2, y2 int) { p.x -= x2 p.y -= y2 } func main() { // 定义一个Point类型的结构体变量 我们可以看成一个实例化的一个`对象` var p1 Point = Point{ 0, 0, } fmt.Printf("P1的初始x = %d, y = %d\n", p1.x, p1.y) p1.forwardTo(9, 6) fmt.Printf("P1前进之后的x = %d, y = %d\n", p1.x, p1.y) // 执行后对原没影响 p1.retreatTo(2,2) fmt.Printf("P1后退之后的x = %d, y = %d\n", p1.x, p1.y) } P1的初始x = 0, y = 0 P1前进之后的x = 9, y = 6 P1后退之后的x = 9, y = 6“Go语言中没有隐藏的this指针”
方法作用的目标是显示传递的方法作用的目标不一定是指针接收器就是方法作用的目标
package main type integer int func (i integer) compareWithNum(x int) bool { if i > integer(x) { return true } else { return false } } func compare(x ,y integer) bool{ if x>y { return true }else{ return false } } func main() { var num integer = 9 // 面向对象的用法 // 显性调用方法 num.compareWithNum(10) // 面向过程的用法 compare(num,88) }