Go 学习笔记(六)- 方法

OOP 在 go 中的应用感觉怪怪的,不过还好比较简单,而且跟传统的 OO 思想完全不同,感觉毁三观。

方法声明

go 的方法非常有意思,在函数名前加个变量和类型,就是为该类型添加了方法。
当然只能在自定义类型上声明方法。

1
2
3
4
5
6
7
8
9
10
type Point struct{ X, Y float64 }
// 为 Point 类型添加 Distance 方法。
func (p Point) Distance(q Point) float64 {
return math.Hypot(q.X-p.X, q.Y-p.Y)
}

// 调用方法
p := Point{1, 2}
q := Point{4, 6}
fmt.Println(p.Distance(q)) // "5", method call

方法的参数 (p Point) 里的 p 叫做方法的接收器(receiver),和传统 OO 不一样,不是 thisself,这里的接收器仅仅是个变量,往往采用类型首字母命名。

基于指针对象的方法

在函数参数调用的时候,其实是复制了一份变量,方法也是一样,所以如果要修改该对象的数据,那么应该使用指针。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import "fmt"

type Point struct{ X, Y int }

func (p Point) SetPoint1(x, y int) {
p.X = x
p.Y = y
}

func (p *Point) SetPoint2(x, y int) {
p.X = x
p.Y = y
}

func main() {
point1 := Point{11, 11}
point2 := Point{11, 11}

point1.SetPoint1(22, 22)
point2.SetPoint2(33, 33)

fmt.Printf("%v\n", point1) // {11 11}
fmt.Printf("%v\n", point2) // {33 33}
}

这个例子可以直接看到区别了,如果不用指针就无法修改对象的值。
其实应该 (&point2).SetPoint2 方式调用,但是编译器帮我们隐式调用了。

通过嵌入结构体来扩展类型

简单描述,就像是继承,只是方式有点怪怪的,跟结构体的嵌入是一样的。

方法值和方法表达式

方法可以当做值赋值给其他变量,方便调用,整理跟 js 有非常大的区别,因为不涉及 context 概念,js 必须通过 bind 来处理,而 go 不需要。

封装

一个对象的变量或者方法如果对调用方是不可见的话,一般就被定义为“封装”。封装有时候也被叫做信息隐藏,同时也是面向对象编程最关键的一个方面。

小结

本章概念不多,但感觉实际应用会踩很多坑,这需要在以后应用中慢慢掌握。
光语法来说,还是非常容易掌握的。