目录
一、结构体定义
Go语言中的基础数据类型可以表示一些事物的基本属性,但是当我们想表达一个事物的全部或部分属性时,这时候再用单一的基本数据类型明显就无法满足需求了,Go语言提供了一种自定义数据类型,可以封装多个基本数据类型,这种数据类型叫结构体,英文名称struct。 也就是我们可以通过struct来定义自己的类型了。
Go语言中通过struct来实现面向对象。
1、结构体的定义
type 类型名 struct {
字段名 字段类型
字段名 字段类型
…
}
1.类型名:标识自定义结构体的名称,在同一个包内不能重复。
2.字段名:表示结构体字段名。结构体中的字段名必须唯一。
3.字段类型:表示结构体字段的具体类型。
举个例子,我们定义一个Person(人)结构体,代码如下:
type person struct {
name string
city string
age int8
}
同样类型的字段也可以写在一行,
type person1 struct {
name, city string
age int8
}
这样我们就拥有了一个person的自定义类型,它有name、city、age三个字段,分别表示姓名、城市和年龄。这样我们使用这个person结构体就能够很方便的在程序中表示和存储人信息了。
2、结构体字段的可见性
结构体中字段大写开头表示可公开访问,小写表示私有(仅在定义当前结构体的包中可访问)。
3、结构体的匿名字段
结构体允许其成员字段在声明时只有类型没有字段名,这种没有名字的字段就称为匿名字段。
//Person 结构体Person类型
type Person struct {
string
int
}
func main() {
p1 := Person{
"pprof.cn",
18,
}
fmt.Printf("%#v\n", p1) //main.Person{string:"pprof.cn", int:18}
fmt.Println(p1.string, p1.int) //pprof.cn 18
}
匿名字段默认采用类型名作为字段名,由于结构体要求字段名称必须唯一,因此一个结构体中同种类型的匿名字段只能有一个。
二、结构体实例化
notes:如果先声明、后实例化。则实例化后才能使用struct
结构体的定义只是一种内存布局的描述,只有当结构体实例化时,才会真正地分配内存。因此必须在定义结构体并实例化后才能使用结构体的字段。
实例化就是根据结构体定义的格式创建一份与格式一致的内存区域,结构体实例与实例间的内存是完全独立的。
1、基本实例化
结构体本身是一种类型,可以像整型、字符串等类型一样,以 var 的方式声明结构体即可完成实例化。
var ins T
type person struct {
name string
city string
age int8
}
func main() {
var p1 person
p1.name = "pprof.cn"
p1.city = "北京"
p1.age = 18
fmt.Printf("p1=%v\n", p1) //p1={pprof.cn 北京 18}
fmt.Printf("p1=%#v\n", p1) //p1=main.person{name:"pprof.cn", city:"北京", age:18}
}
2、针类型实例化
Go 语言中,还可以使用 new 关键字对类型(包括结构体、整型、浮点数、字符串等)进行实例化,结构体在实例化后会形成指针类型的结构体。
使用 new 的格式如下:
ins := new(T)
Go 语言让我们可以像访问普通结构体一样使用.访问结构体指针的成员。
type Player struct{
Name string
HealthPoint int
MagicPoint int
}
//指针类型
tank := new(Player)
tank.Name = "Canon"
tank.HealthPoint = 300
经过 new 实例化的结构体实例在成员赋值上与基本实例化的写法一致。
3、取地址实例化
在 Go 语言中,对结构体进行&取地址操作时,视为对该类型进行一次 new 的实例化操作。取地址格式如下:
ins := &T{}
下面使用结构体定义一个命令行指令(Command),指令中包含名称、变量关联和注释等。对 Command 进行指针地址的实例化,并完成赋值过程,代码如下:
type Command struct {
Name string // 指令名称
Var *int // 指令绑定的变量
Comment string // 指令的注释
}
var version int = 1
cmd := &Command{}
cmd.Name = "version"
cmd.Var = &version
cmd.Comment = "show version"
重点:取地址实例化是最广泛的一种结构体实例化方式。
func newCommand(name string, varref *int, comment string) *Command {
return &Command{
Name: name,
Var: varref,
Comment: comment,
}
}
cmd = newCommand(
"version",
&version,
"show version",
)
三、结构体初始化
结构体在实例化时可以直接对成员变量进行初始化。相当于实例化时直接赋值
1、两种初始化的方式
初始化也有两种方式,直接初始化,取地址初始化
//1、直接实例化
p5 := person{
name: "pprof.cn",
city: "北京",
age: 18, //最后一个逗号必须存在,否则会报错
}
//2、取地址实例化
p6 := &person{
name: "pprof.cn",
city: "北京",
age: 18, //最后一个逗号必须存在,否则会报错
}
//备注:没有指针类型的初始化
2、使用“键值对",值列表两种初始化
一种是字段“键值对”形式及多个值的列表形式。键值对形式的初始化适合选择性填充字段较多的结构体;
多个值的列表形式适合填充字段较少的结构体。(说白了就是不写key,直接写value)
(1)使用“键值对”初始化结构体
键值对的填充是可选的,不需要初始化的字段可以不填入初始化列表中。
结构体实例化后字段的默认值是字段类型的默认值,例如:数值为 0,字符串为空字符串,布尔为 false,指针为 nil 等。
键值对初始化的格式如下:
ins := 结构体类型名{
字段1: 字段1的值,
字段2: 字段2的值,
…
}
//示例一:
p5 := person{
name: "pprof.cn",
city: "北京",
age: 18, //最后一个逗号必须存在,否则会报错
}
fmt.Printf("p5=%#v\n", p5) //p5=main.person{name:"pprof.cn", city:"北京", age:18}
//示例二:也可以对结构体指针进行键值对初始化
p6 := &person{
name: "pprof.cn",
city: "北京",
age: 18, //最后一个逗号必须存在,否则会报错
}
fmt.Printf("p6=%#v\n", p6) //p6=&main.person{name:"pprof.cn", city:"北京", age:18}
(2)使用值的列表初始化
初始化结构体的时候可以简写,也就是初始化的时候不写键,直接写值:
p8 := &person{
"pprof.cn",
"北京",
18,
}
fmt.Printf("p8=%#v\n", p8) //p8=&main.person{name:"pprof.cn", city:"北京", age:18}
使用这种格式初始化时,需要注意:
- 必须初始化结构体的所有字段。
- 初始值的填充顺序必须与字段在结构体中的声明顺序一致。
- 该方式不能和键值初始化方式混用。(也就是不能一下写键,一下不写键)
四、使用结构体实现构造函数
go的类型或结构体没有构造函数的功能。结构体的初始化过程可以使用函数封装实现。
因为struct是值类型,如果结构体比较复杂的话,值拷贝性能开销会比较大,所以该构造函数返回的是结构体指针类型。
func newPerson(name, city string, age int8) *person {
return &person{
name: name,
city: city,
age: age,
}
}
调用构造函数
p9 := newPerson("pprof.cn", "测试", 90)
fmt.Printf("%#v\n", p9)
五、结构体的“继承”
Go语言中使用结构体也可以实现其他编程语言中面向对象的继承。
说明:这种只是模拟“继承”
//Animal 动物
type Animal struct {
name string
}
func (a *Animal) move() {
fmt.Printf("%s会动!\n", a.name)
}
//Dog 狗
type Dog struct {
Feet int8
*Animal //通过嵌套匿名结构体实现继承
}
func (d *Dog) wang() {
fmt.Printf("%s会汪汪汪~\n", d.name)
}
func main() {
d1 := &Dog{
Feet: 4,
Animal: &Animal{ //注意嵌套的是结构体指针
name: "乐乐",
},
}
d1.wang() //乐乐会汪汪汪~
d1.move() //乐乐会动!
}