153 lines
3.4 KiB
Markdown
153 lines
3.4 KiB
Markdown
### 方法
|
||
- Go 语言中的方法的本质就是,一个以方法的 receiver 参数作为第一个参数的普通函数
|
||
![](https://blog-heysq-1255479807.cos.ap-beijing.myqcloud.com/blog/wiki/go/methods.jpg)
|
||
- 方法支持赋值给变量,相当于第一个参数是结构体自身或者自身的指针类型
|
||
```go
|
||
package main
|
||
|
||
import "fmt"
|
||
|
||
type T struct{}
|
||
|
||
func (t *T) M(n int) {
|
||
fmt.Println(n)
|
||
}
|
||
|
||
func (t T)N(n int) {
|
||
fmt.Println(n)
|
||
}
|
||
|
||
func main() {
|
||
m1 := (*T).M
|
||
m1(&T{}, 2)
|
||
|
||
m2 := T.N
|
||
m2(T{}, 3)
|
||
}
|
||
```
|
||
|
||
### 方法接收receiver
|
||
```go
|
||
func (t *T或T) MethodName(参数列表) (返回值列表) {
|
||
// 方法体
|
||
}
|
||
```
|
||
- T为基类型
|
||
- receiver 参数的基类型本身不能为指针类型或接口类型
|
||
- 每个方法只能有一个 receiver 参数
|
||
- Go 不支持在方法的 receiver 部分放置包含多个 receiver 参数的参数列表,或者变长 receiver 参数
|
||
- 方法接收器(receiver)参数、函数 / 方法参数,以及返回值变量对应的作用域范围,都是函数 / 方法体对应的显式代码块
|
||
- receiver 部分的参数名不能与方法参数列表中的形参名,以及具名返回值中的变量名存在冲突,必须在这个方法的作用域中具有唯一性
|
||
- 如果在方法体中,我们没有用到 receiver 参数,我们也可以省略 receiver 的参数名
|
||
|
||
### 方法声明约束
|
||
- 方法声明要与 receiver 参数的基类型声明放在同一个包内
|
||
- 不能为原生类型(诸如 int、float64、map 等)添加方法
|
||
- 不能跨越 Go 包为其他包的类型声明新方法
|
||
|
||
### 选择receiver 原则
|
||
- 如果需要修改receiver内部属性,使用指针类型
|
||
- 不需要修改内部属性,使用结构体类型,传参值拷贝,但是结构体过大时,选用指针类型
|
||
- 如果 T 类型需要实现某个接口,那就要使用 T 作为 receiver 参数的类型,来满足接口类型方法集合中的所有方法
|
||
|
||
### 方法集合
|
||
```go
|
||
- 用来判断一个类型是否实现了某接口类型的唯一手段
|
||
- T类型实现了M1方法
|
||
- *T类型实现了M1和M2方法
|
||
type Interface interface {
|
||
M1()
|
||
M2()
|
||
}
|
||
|
||
type T struct{}
|
||
|
||
func (t T) M1() {}
|
||
func (t *T) M2() {}
|
||
|
||
func main() {
|
||
var t T
|
||
var pt *T
|
||
var i Interface
|
||
|
||
i = pt
|
||
i = t // cannot use t (type T) as type Interface in assignment: T does not implement Interface (M2 method has pointer receiver)
|
||
}
|
||
```
|
||
|
||
### type定义的新类型和命名的类型的方法集合
|
||
- 自定义非接口类型的 defined 类型的方法集合为空
|
||
- 自定义接口类型的 defined 类型的方法集合为接口的方法
|
||
```go
|
||
package main
|
||
|
||
type T struct{}
|
||
|
||
func (T) M1() {}
|
||
func (*T) M2() {}
|
||
|
||
type T1 T
|
||
|
||
func main() {
|
||
var t T
|
||
var pt *T
|
||
var t1 T1
|
||
var pt1 *T1
|
||
|
||
dumpMethodSet(t)
|
||
dumpMethodSet(t1)
|
||
|
||
dumpMethodSet(pt)
|
||
dumpMethodSet(pt1)
|
||
}
|
||
|
||
|
||
main.T's method set:
|
||
- M1
|
||
|
||
main.T1's method set is empty!
|
||
|
||
*main.T's method set:
|
||
- M1
|
||
- M2
|
||
|
||
*main.T1's method set is empty!
|
||
```
|
||
- 无论原类型是接口类型还是非接口类型,类型别名都与原类型拥有完全相同的方法集合
|
||
```go
|
||
|
||
type T struct{}
|
||
|
||
func (T) M1() {}
|
||
func (*T) M2() {}
|
||
|
||
type T1 = T
|
||
|
||
func main() {
|
||
var t T
|
||
var pt *T
|
||
var t1 T1
|
||
var pt1 *T1
|
||
|
||
dumpMethodSet(t)
|
||
dumpMethodSet(t1)
|
||
|
||
dumpMethodSet(pt)
|
||
dumpMethodSet(pt1)
|
||
}
|
||
|
||
|
||
main.T's method set:
|
||
- M1
|
||
|
||
main.T's method set:
|
||
- M1
|
||
|
||
*main.T's method set:
|
||
- M1
|
||
- M2
|
||
|
||
*main.T's method set:
|
||
- M1
|
||
- M2
|
||
``` |