Contents
5.4. 接收器-方法作用的目标¶
接收器的格式如下:
func (接收器变量 接收器类型) 方法名(参数列表)(返回参数){
函数体
}
· 接收器变量:官方建议使用接收器类型名第一个小写字母。
· 接收器类型:接收器类型和参数类似,可以是指针类型和非指针类型
· 方法名、参数列表、返回参数:格式与函数定义一致。
接收器根据接收器的类型可以分为指针接收器、非指针接收器,两种接收器在使用时会产生不同的效果。
5.4.1. 1.指针类型的接收器¶
package main
import "fmt"
// 定义属性结构
type Property struct {
value int
}
// 设置属性值
func (p *Property) SetValue(v int) {
// 修改p的成员变量
p.value = v
}
// 获取属性值
func (p *Property) Value() int {
return p.value
}
func main() {
// 实例化属性
p := new(Property)
// 设置值
p.SetValue(100)
// 打印值
fmt.Println(p.Value()) //100
}
5.4.2. 2.理解非指针类型的接收器¶
当方法作用于非指针接收器时,Go语言会在代码运行时将接收器的值复制一份,在非指针接收器的方法中可以获取接收器的成员值,但修改后无效。
package main
import "fmt"
// 定义点结构
type Point struct {
X int
Y int
}
// 非指针接收器的加方法
func (p Point) Add(other Point) Point {
// 成员值与参数相加后返回新的结构
return Point{p.X + other.X, p.Y + other.Y}
}
func main() {
// 初始化点
p := Point{1, 1}
p2 := Point{2, 2}
// 与另外一个点相加
result := p.Add(p2)
// 输出结果
fmt.Println(result) //{3 3}
}
5.4.3. 3.指针和非指针接收器的使用¶
小对象由于值复制时的速度较快,所以适合使用非指针接收器。
大对象因为复制性能较低,适合使用指针接收器,在接收器和参数间传递时不进行复制,只是传递指针。
5.4.4. 4.为类型添加方法¶
4.1 为基本类型添加方法¶
判断一个值是否为0
func main() {
var v int = 0
if v == 0 {
fmt.Println("v = 0")
}
}
如果v当做整型对象,那么就可以增加一个IsZero()方法。
package main
import "fmt"
// 将int定义为MyInt,将int定义为自定义的MyInt类型
type MyInt int
// 为MyInt添加IsZero()方法,该方法使用了非指针接收器,数值类型没有必要使用指针接收器
func (m MyInt) IsZero() bool {
return m == 0
}
//为MyInt添加Add()方法,将m从MyInt类型转换为int类型后再计算
func (m MyInt) Add(other int) int {
return other + int(m)
}
func main() {
var b MyInt
fmt.Println(b.IsZero()) //true
b = 1
fmt.Println(b.Add(2)) //3
}
4.2 http包中的类型方法¶
Go语言提供的http包里也大量使用了类型方法
代码示例:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"
)
func main() {
client := &http.Client{}
// 创建一个http请求
req, err1 := http.NewRequest("POST", "http://www.163.com/", strings.NewReader("key=value"))
//发现错误就打印并退出
if err1 != nil {
fmt.Println(err1)
os.Exit(1)
return
}
// 为标头添加信息
req.Header.Add("User-Agent", "myClient")
//开始请求
resp, err2 := client.Do(req)
// 处理请求的错误
if err2 != nil {
fmt.Println(err2)
os.Exit(1)
return
}
// 读取服务器返回的内容
data, err3 := ioutil.ReadAll(resp.Body)
if err3 != nil {
fmt.Println(err2)
os.Exit(1)
return
}
fmt.Println(string(data))
// 最后调用defer,关闭上下文
defer req.Body.Close()
}
http.Header 就是典型的自定义类型,并拥有自己的方法。http.Header的部分定义如下:
添加一个Header非指针接收器,Add()方法需要传入2个string的值
func (h Header) Add(key, value string) {
textproto.MIMEHeader(h).Add(key, value)
}
func (h Header) Set(key, value string) {
textproto.MIMEHeader(h).Set(key, value)
}
func (h Header) Get(key string) string {
return textproto.MIMEHeader(h).Get(key)
4.3 time包中的类型方法¶
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println(time.Second.String())
}
time.Second是一个常量,源码如下:
const (
Nanosecond Duration = 1
Microsecond = 1000 * Nanosecond
Millisecond = 1000 * Microsecond
Second = 1000 * Millisecond
Minute = 60 * Second
Hour = 60 * Minute
)
5.4.5. 5.示例:使用事件系统实现事件的响应和处理¶
1.方法和函数的统一调用
package main
import "fmt"
// 声明一个结构体
type class struct {
}
// 给结构体添加Do方法,参数为整型,打印和输入参数值
func (c *class) Do(v int) {
fmt.Println("call method do:", v)
}
// 普通函数的Do方法,参数也是整型,打印和输入参数值
func funcDo(v int) {
fmt.Println("call function do:", v)
}
func main() {
// 声明一个函数回调
var delegate func(int)
// 创建结构体的实例
c := new(class)
// 将回调函数设为c的Do方法
delegate = c.Do
// 调用
delegate(100) //call method do: 100
// 将回调设为普通函数
delegate = funcDo
// 调用
delegate(100) //call function do: 100
}