文章目录
- 1、前言
- 2、结构体的定义与声明和使用
- 2.1、结构体的定义
- 2.2、结构体的声明
- 2.3、结构体的使用
- 2.3.1、函数参数之传递值拷贝
- 2.3.2、函数参数之传递指针拷贝
- 2.3.3、结构体的方法
- 2.3.3.1、以值为接收体
- 2.3.3.2、以指针为接收体
- 3、结构体的嵌套
- 3.1、入门案例
- 3.2、需要注意的点
1、前言
- 在 Go 语言中不存在 Class 类这种概念,但是存在 struct 结构体,可以代替实现 Class 的功能,并且 Go 语言中也不存在继承,但是可以通过结构体嵌套实现类似 Java 中的继承。
2、结构体的定义与声明和使用
2.1、结构体的定义
type Hero struct {
bloodVolume uint16
name string
age uint8
}
2.2、结构体的声明
- 方式一:通过内置方法 new,得到一个指向结构体的指针。
var hero = new(Hero)
hero.bloodVolume = 100
hero.name = "项羽"
hero.age = 27
- 方式二:通过取地址符 “&” 直接得到一个指向结构体的指针。
hero := &Hero{
bloodVolume: 100,
name: "嬴政",
age: 27,
}
- 方式三:最一般的方式,获得的不是指针。
hero := Hero{
bloodVolume: 100,
name: "嬴政",
age: 27,
}
2.3、结构体的使用
2.3.1、函数参数之传递值拷贝
type Hero struct {
BloodVolume uint16
Name string
Age uint8
}
func Method1(h Hero) {
h.Age++
fmt.Println("method1.", h)
}
func main() {
hero := Struct.Hero{
BloodVolume: 100,
Name: "嬴政",
Age: 27,
}
fmt.Println("main.", hero)
Struct.Method1(hero)
fmt.Println("main.", hero)
}
- 执行以上程序,输出结果如下:
main. {100 嬴政 27}
method1. {100 嬴政 28}
main. {100 嬴政 27}
- 可见,当传入的结构体是值拷贝时,在函数内修改结构体的值,不会对原来结构体造成影响。
2.3.2、函数参数之传递指针拷贝
func Method2(h *Hero) {
(*h).Age++
fmt.Println("method2.", *h)
}
func main() {
hero := Struct.Hero{
BloodVolume: 100,
Name: "嬴政",
Age: 27,
}
fmt.Println("main.", hero)
Struct.Method2(&hero)
fmt.Println("main.", hero)
}
- 执行以上程序,输出结果如下:
main. {100 嬴政 27}
method2. {100 嬴政 28}
main. {100 嬴政 28}
- 可见,当传入的结构体是指针拷贝时,在函数内修改结构体的值,会对原来结构体造成影响。
2.3.3、结构体的方法
2.3.3.1、以值为接收体
func (h Hero) SetBloodVolume(v uint16) {
h.BloodVolume = v
}
func main() {
hero := Struct.Hero{
BloodVolume: 100,
Name: "嬴政",
Age: 27,
}
hero.SetBloodVolume(90)
fmt.Println(hero)
}
- 执行结果如下:
{100 嬴政 27}
- 发现以值为接收体,在方法内对结构体对象进行修改,不会对原本结构体对象造成影响,因为地址都不一样啊。
2.3.3.2、以指针为接收体
func (h *Hero) SetBloodVolume2(v uint16) {
h.BloodVolume = v
fmt.Printf("SetBloodVolume2.%p\n", h)
}
func main() {
hero := Struct.Hero{
BloodVolume: 100,
Name: "嬴政",
Age: 27,
}
hero.SetBloodVolume2(90)
fmt.Printf("main.%p\n", &hero)
fmt.Println(hero)
}
- 输出结果如下:
SetBloodVolume2.0xc0000044a0
main.0xc0000044a0
{90 嬴政 27}
- 发现以指针为接收体,在方法内对结构体对象进行修改,会对原本结构体对象造成影响,因为地址一样啊。
3、结构体的嵌套
3.1、入门案例
- 在 Java 中,子类继承父类,子类就可以获得父类定义的方法和属性,虽然在 Go 语言中,不存在继承这个概念,但是在 Go 中通过嵌套,姑且称被嵌套的结构体为基结构体,嵌套其他结构体的结构体就叫派生结构体吧,这样派生结构体就“继承”了基结构体的属性和方法,看示例代码:
type Creature struct {
Kind string
}
type Animal struct {
Creature
}
type Dog struct {
Animal
}
func (c Creature) Breath() {
fmt.Println("会呼吸")
}
func TestInherit() {
d := Dog{Animal{Creature{Kind: "生物"}}}
fmt.Println(d.Kind)
d.Breath()
}
- 这里我来了个套娃,Dog 套 Animal,Animal 套 Creature,尽管这样,Dog 依然能调用 Creature 的方法,并且能访问它的属性 Kind,执行结果如下:
生物
会呼吸
3.2、需要注意的点
- 虽然派生结构体可以调用基结构体的方法,访问它的属性,但它并不是严格意义上的继承,在 Java 中,子类继承了父类,那么可以让“父类 = 子类”,但是 Go 中不可以,可以看以下示例代码:
func Method1(c Creature) {
}
func main() {
d := Dog{Animal{Creature{Kind: "生物"}}}
Method1(d) //编译阶段报错:cannot use d (type Dog) as type Creature in argument to Method1
}
- 包括像下面这段代码,更是不能被允许!
func Method2(d Dog) {
}
func main() {
c := Interface.Creature{Kind: "生物"}
Interface.Method2(c) //编译阶段报错:cannot use c (type Creature) as type Dog in argument to Method2
}