可以先看:go的数据类型
下面是针对不同类型,方法如何定义和使用。
1、方法定义
go可以为任意类型定义方法!!【指针类型除外】
方法比函数的好处:方法名可以简短。当我们在包外调用的时候这种好处就会被放大,因为我们可以使用这个短名字,而可以省略掉包的名字。
在函数声明时,在其名字之前放上一个变量
,即是一个方法。这个附加的参数会将该函数附加到这种类型上,即相当于为这种类型定义了一个独占的方法。
(1)两种接收器声明方式:
接收器是类型对象
:
func (p Point) ScaleBy(factor float64) {xx}
接收器是类型指针对象
:
一般会约定如果Point这个类有一个指针作为接收器的方法
,那么所有Point的方法都必须有一个指针接收器
,即使是那些并不需要这个指针接收器的函数。
func (p *Point) ScaleBy(factor float64) {xx}
(2)指针类型的方法
go不能
直接定义指针类型的方法
!!!说的是下面这种情况,因为接收器放类型和指针都不对:
type intPoint *int
//func (?) addThree() int{
// return
//}
func main(){
tmp := 10
var b intPoint = &tmp
// fmt.Print(b.addThree()) //指针类型的方法addThree没法定义,当然也就没法调用
}
但是,我们可以换个方式,用指针变量调用指针对应原类型
的方法。调用方式有2种:
type myInt int
func (i myInt) addOne() myInt {
return i + 1
}
func (i *myInt) addTwo() myInt {
return *i + 2
}
func main(){
//方式1
var a myInt = 2 // a是myInt类型
a.addOne() // a不变
fmt.Println(a) // 2
(&a).addTwo() //取地址即指针。传指针,a变
fmt.Println(a) // 4
//方式2
b := new(myInt) // b是*myInt类型,指针
*b = 10
// 传值,b不变
(*b).addOne() // 正常访问,传入myInt类型
fmt.Println(*b)
b.addOne() // go自己处理,传入*myInt自动转为myInt类型
fmt.Println("b:", *b)
//下面传入指针,b会变
b.addTwo() // 正常访问,传入*myInt类型。
fmt.Println(*b)
(*b).addTwo() // go自己处理,传入myInt自动转为*myInt类型
fmt.Println(*b)
}
(3)
如果命名类型T(译注:用type xxx定义的类型)的所有方法都是用T类型自己来做接收器(而不是*T),那么拷贝这种类型的实例就是安全的;调用他的任何一个方法也就会产生一个值的拷贝。比如time.Duration的这个类型,在调用其方法时就会被全部拷贝一份,包括在作为参数传入函数的时候。
但是如果一个方法使用指针作为接收器
,你需要避免对其进行拷贝
,因为这样可能会破坏掉该类型内部的不变性
。比如你对bytes.Buffer对象进行了拷贝,那么可能会引起原始对象和拷贝对象只是别名而已,实际上它们指向的对象是一样的。紧接着对拷贝后的变量进行修改可能会有让你有意外的结果。
译注: 作者这里说的比较绕,其实有两点:
1 不管你的method的receiver是指针类型还是非指针类型,都是可以通过指针/非指针类型进行调用的,编译器会帮你做类型转换。
2 在声明一个method的receiver该是指针还是非指针类型时,你需要考虑两方面的因素,第一方面是这个对象本身是不是特别大,如果声明为非指针变量时,调用会产生一次拷贝;第二方面是如果你用指针类型作为receiver,那么你一定要注意,这种指针类型指向的始终是一块内存地址,就算你对其进行了拷贝。熟悉C或者C++的人这里应该很快能明白。//没懂
参考:
https://blog.csdn.net/u013862108/article/details/105028124
https://docs.hacknode.org/gopl-zh/ch6/ch6-02.html
2、实现接口的表示:接收器不能是指针!!
接收参数person不可以是指针类型,否则不认为是实现了接口
参考:
https://www.cnblogs.com/craneboos/p/8615476.html