Go语言中的结构体和方法

Go语言仅支持封装,不像其他语言一样支持继承和多态。

Go语言没有Class,只有struct

结构的定义

1
2
3
4
5
6
type person struct {
name string
age int
height float64
weight float64
}

这样,我们就定义了一个对象出来,那么如何使用呢?

我们实例化tony这个人,并且使用.来访问结构的成员:

1
2
3
4
5
6
7
func main() {
tony := person{name: "tony"}

tony.height = 1.68
fmt.Printf("Name: %s\n", tony.name)
fmt.Printf("Height: %.2fm\n", tony.height)
}

输出

1
2
Name: tony
Height: 1.68m

而对于没有赋值的age、height、weight来说,他们默认则是相应类型初始化的默认值。

1
2
3
4
5
6
7
func main() {
tony := person{name: "tony"}

tony.height = 1.68
fmt.Printf("Name: %s\n", tony.name)
fmt.Printf("Height: %.2fm\n", tony.height)
}

输出:

1
2
3
Name: tony
Height: 1.68m
0 0

为结构定义方法

如果我们想为person添加一个方法,将这个实例所有的成员全部打印出来呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
type person struct {
name string
age int
height float64
weight float64
}

// 为person定义print方法,(p person)被称为接受者
func (p person) print() {
fmt.Println(p.name, p.age, p.weight, p.height)
}

func main() {
tony := person{name: "tony",height: 1.68}
// 通过.来调用print方法
tony.print()
}

输出:

1
tony 0 0 1.68

那么,如果我想通过定义一个方法,通过传值来修改结构成员的值呢?看一下下面的代码是否可行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
type person struct {
name string
age int
height float64
weight float64
}

// 我们在方法里面,对传进来的person的实例的age进行修改
func (p person) changeAge(age int) {
p.age = age
}

func main() {
tony := person{name: "tony",age: 18}
fmt.Println(tony.age)

// 使用方法修改age的值
tony.changeAge(20)
fmt.Println(tony.age)
}

输出结果:

1
2
18
18

为什么age的值没有被修改呢?因为Go语言是值传递,在使用changeAge方法时,传入的实际上是tony.age值的拷贝,所以tony.age的值并没有被修改。因此我们需要将传入的值,设置为指针类型。

1
2
3
func (p *person) changeAge(age int) {
p.age = age
}

完整代码:

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

import "fmt"

type person struct {
name string
age int
height float64
weight float64
}

// 我们在方法里面,对传进来的person的实例的age进行修改
func (p *person) changeAge(age int) {
p.age = age
}

func main() {
tony := person{name: "tony", age: 18}
fmt.Println(tony.age)

// 使用方法修改age的值
tony.changeAge(20)
fmt.Println(tony.age)
}

输出:

1
2
18
20

值接受者 vs 指针接受者

值接受者是Go语言特有的

  • 要改变内容必须使用指针接受者

  • 结构过大也考虑使用指针接受者

  • 一致性:如果有指针接受者,最好都是用指针接受者