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)
}
func Method2 ( d Dog) {
}
func main ( ) {
c := Interface. Creature{ Kind: "生物" }
Interface. Method2 ( c)
}