Golang OOP

Struct

Go 用struct 实现OOP, 匿名字段可看作实现了继承关系,子类也可以重写父类的方法。

Note, there is also exported and unexported fields in struct, the same pattern like exported and unexported variable, func and method.

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// Person 在Student中成为了匿名字段
// 直接被访问,也叫提升字段
type Person struct {
name string
age int
}

type Student struct {
Person // 匿名字段,模拟继承结构 or *Person
school string
}

type Student struct {
person Person // 普通嵌套字段,必须逐层访问
school string
}
// You can declare a method on non-struct types, too.

// method,会自动关联到对应的struct
// non-pointer receiver is not common! please don't use it!
func (p Person) getName() {
return p.name
}

// 指针类型 is used to modify struct variable!
// Since methods often need to modify their receiver
// pointer receivers are more common than value receivers.
func (p *Person) setAge() {
p.age = p.age + 10
}

// Student子类重写了 Person 父类的方法
func (s Student) getName() {
return "studnet " + s.name
}

func main() {
s1 := Student{Person: Person{name: "xxx", age:12}, school: "yyy"}
// or omit the field name:
s1 := Student{Person{"xxx", 12}, school: "yyy"}
// 匿名字段 和 嵌套字段(逐层)的访问
// 因为提升字段的原因,可以把Person省掉
// s1.name or s1.Person.name
// s1.age or s1.Person.age
// s1.school

// vaule s1 calls a pointer receiver method
s1.setAge() // call is interpreted as (&s1).setAge()

s2 := &Person{"people", 23}
// pointer s2 calls a value receiver method
s2.getName() // call is interpreted as (*s2).getName()
}

Interface

在Go中,interface 定义方法的声明signature,具体类型实现方法的定义.

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
27
28
29
30
31
32
33
34
35
36
37
38
// interface define
type Usb interface {
// normal function definition
start()
end()
}

type Mouse struct {
name string
}

// 实现接口,会自动关联
// 相当于Java 中 class xxx implements xxx
// 虽然这里没有写出来interface的名字
// 不能写成(m *Mouse)
func (m Mouse) start() {
fmt.Println("Mouse start")
}
func (m Mouse) end() {
fmt.Println("Mouse end")
}

// 测试使用接口
func testUsb(usb Usb) {
// usb 实际上就是实现了接口的Mouse
usb.start()
usb.end()
}

m := Mouse {name: "xxx"}
testUsb(m)

// 或者声明interface 变量
var u Usb
// u 不能访问 m 的字段
u = m
u.start()
u.end()

空接口,没有方法,所以可以认为所有类型都实现了它,可以用作函数的参数去接收任何数据类型。 The main usage of empty interface is func arguments.

1
2
3
4
5
6
7
8
9
10
11
12
type A interface {}
// because all type implicitly implements empty interface
// so we can use interface{} as var type
var a1 A = "hello"
var a2 A = 123
var a3 A = true
var a4 interface{} = "hello"

// map value存储任意类型
var map1 = make(map[string]interface{})
// slice 存储任意类型
var slice1 = make([]interface{})

注意fmt.Println() 就是这么实现的,用的匿名的空接口。

1
2
3
4
// 可变参数 + 匿名空接口
func Println(a ...interface{}) (n int, err error) {
return Fprintln(os.Stdout, a...)
}

How to 判断接口对应的具体类型呢,语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// instance: 解析后的实际类型
// ok: true or false
// 接口对象: 接口名
// 实际类型: 猜测的实际类型
instance := 接口对象.(实际类型) // panic may occur
instance, ok := 接口对象.(实际类型) // safe way

switch 接口对象.(type) {
case string:
...
case int:
...
case Person:
...
}

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
type A interface {}

// 实例的指针值也可以传进来
func getType(a A) {
// 判断a 具体是什么类型
if ins, ok := a.(int), ok {

}
// 结构体类型
// 如果传进来的是指针,则写成,a.(*Person)
if ins, ok := a.(Person), ok {

}

// 或者用switch
switch ins := a.(type) {
case int:
// pass
case Person:
// pass
}
}

接口还可以多继承, 实现C的类型必须要实现C中自身和继承的所有的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
type A interface {
testA()
}

type B interface {
testB()
}

type C interface {
A
B
testC()
}
0%