func (receiver receiverType) funcName(parameters) (results)
// 1. receiver 为任意名字。
// 2. receiverType为调用者的类型。可以是T或者*T。注意T本身不能是接口或者指针。
例如T=int,但是不能是*int。想要指针可以这样做:T=int后,单独加一个*。
// 代码解释:
// 1. 正确写法
type myint int
func (s *myint) Add() (r int)
// 2. 错误写法。因为T类型本身不能是指针。
type myintp *int
func (s myintp) Add() (r int)
5)方法不支持重载,即不支持同样类型中,函数名相同形参不同的方法。注意,不同的类型中,是可以有同样的函数名的。下面例子将会解释到。
2 面向过程和面向对象的函数区别
非常简单,就是将函数封装到了一个对象里面,然后通过变量名 + 点的形式进行调用。利用下面的例子。
package main
import "fmt"
// go本身没有long类型
type long int
func Add01(a, b long)long{
return a + b
}
func (t long)Add02(b long)long{
return t + b
}
func main(){
// 1. 面向过程
fmt.Println("Add01 = ", Add01(1, 2))
// 2. 面向对象
var s1 long = 1
fmt.Println("Add02 = ", s1.Add02(5))
}
3 结构体类型添加方法
package main
import "fmt"
type Persion struct {
name string
sex byte
age int
}
// 带有接受者的函数叫方法
func (t Persion) PrintInfo(){
fmt.Println("PrintInfo = ", t)
}
func (t *Persion) SetInfo(n string, s byte, a int){
t.name = n
t.sex = s
t.age = a
}
func main(){
// 1. 普通变量作为隐含实例传参
p := Persion{"hc", 'w', 24}
p.PrintInfo()
// 2. 指针变量作为隐含实例传参
(&p).SetInfo("lqq", 'w', 24)
p.PrintInfo()
}
4 方法相关注意点
1)接收者本身不能是指针类型,上面在将第1点时也强调过。
// 1. 正确的写法
type long int
func (t long)test(){
}
// 2. 错误的写法
// err:Invalid receiver type 'pointer' ('pointer' is a pointer type)
type pointer *int
func (t pointer)test(){
}
2)go的方法不支持重载。例如下面这样写语法是会报错的。因为接收者的类型一样,并且名字也一样。
type long int
func (t long)test(){
}
type long int
func (t long)test(a int){
}
而下面这样写不会报错,因为接收者类型不一样。可以用C++定义了两个类,类中有同样的成员函数名去理解。
type long int
func (t long)test(){
}
type char byte
func (c char) test(a int){
}
5 接收者的值语义和引用语义
1)普通变量作为接收者是值传递。2)指针变量作为接收者是引用传递。代码看回上面第3点的 结构体类型添加方法。 6 指针类型和变量类型的方法集
方法集实际上是使用指针可以如何调用方法,以及普通变量如何调用方法而已。变量在调用自己的方法集时,不受变量自己是指针还是普通变量的约束,都可以使用 “变量名 + 点(.) + 方法名” 的形式调用。
例如:
package main
import "fmt"
type Persion struct {
name string
sex byte
age int
}
// 带有接受者的函数叫方法
func (t Persion) SetInfoValue(){
fmt.Println("SetInfoValue")
}
func (t *Persion) SetInfoPointer(){
fmt.Println("SetInfoPointer")
}
func main(){
// 1. 结构体变量是一个指针时,它能调用哪些方法,就是一个方法集
// 指针调用方法的方式
p := &Persion{"hc", 'w', 24}
p.SetInfoPointer()
p.SetInfoValue() // 它内部会自动转换,将指针p转成 (*p).SetInfoValue(),所以下面的调用方式也是可以的,所以调用方法时不需要考虑是指针还是变量
(*p).SetInfoValue()
fmt.Println("===========")
// 2. 普通变量调用方法的方式
p2 := Persion{"lqq", 'w', 24}
p2.SetInfoValue()
p2.SetInfoPointer() // 内部转成(&p2).SetInfoPointer(),所以下面的调用方式也是可以的
(&p2).SetInfoPointer()
}
7 方法的继承
package main
import "fmt"
type Persion struct {
name string
sex byte
age int
}
// Persion实现了一个方法
func (t *Persion) PrintInfo(){
fmt.Printf("name=%s, byte=%c, age=%d\n", t.name, t.sex, t.age)
}
// 另一个结构体继承了该Persion,它会继承了所有成员及其方法
type Student struct {
Persion // 匿名字段
id int
addr string
}
func main(){
s := Student{Persion{"hc", 'w', 24}, 1, "sz"}
s.PrintInfo()
}
8 方法的重写
go中方法的重写,实际上就是C++的多态(通过虚基类指针、virtual关键字实现)。
下面的go实现多态的例子。
package main
import "fmt"
type Persion struct {
name string
sex byte
age int
}
// Persion实现了一个方法
func (t *Persion) PrintInfo(){
fmt.Printf("name=%s, byte=%c, age=%d\n", t.name, t.sex, t.age)
}
// 另一个结构体继承了该Persion,它会继承了所有成员及其方法
type Student struct {
Persion // 匿名字段
id int
addr string
}
// Student也添加一个同名的方法PrintInfo
// 注意,因为接收者类型一个是 *Persion、一个是 *Student,它们是不一样的,所以函数名可以同样。
// 这样也叫方法的重写,即实现了多态。
func (t *Student) PrintInfo(){
fmt.Println("stu = ", t)
}
func main(){
s := Student{Persion{"hc", 'w', 24}, 1, "sz"}
// 根据就近原则,调用的是Student.PrintInfo()
s.PrintInfo()
// 显示调用才能调用到Persion的PrintInfo()
s.Persion.PrintInfo()
}
9 方法值与方法表达式
1)方法值:隐式调用,通过隐式保存接收者来进行调用。2)方法表达式:显示调用,不会隐式保存接收者,调用时需要显示传实例给对应的接收者类型。
代码例子:
package main
import "fmt"
type Persion struct {
name string
sex byte
age int
}
// 带有接受者的函数叫方法
func (t Persion) SetInfoValue(){
fmt.Println("SetInfoValue")
}
func (t *Persion) SetInfoPointer(){
fmt.Println("SetInfoPointer")
}
func main(){
// 1. 方法值调用
p := &Persion{"hc", 'w', 24}
pFunc := p.SetInfoPointer // 会隐式保存接收者
pFunc()
vFunc := p.SetInfoValue
vFunc()
fmt.Println("==============")
// 2. 方法表达式调用
p2 := Persion{"lqq", 'w', 24}
f := (*Persion).SetInfoPointer // 不会隐式保存接收者,所以调用时需要传对应的实例给接收者。(*Persion)表示传实例时是一个地址而不是普通变量。
f(&p2) // 需要传实例给接收者类型。
f2 := (Persion).SetInfoValue // Persion表示传实例时是一个普通变量而不是地址。
f2(p2) // 需要传实例给接收者类型。
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)