Go语言中基础数据类型可以表示事物的基本属性,但是当要表达事物的全部或部分属性时,用单一的基本数据类型无法满足需求,Go中提供了一种自定义数据类型,可以封装多个基本数据类型,该数据类型叫结构体,英文名struct。Go语言中没有“类”的概念,也不支持“类”的继承等面向对象的概念。不过 Go语言可以通过struct来实现面向对象。
1、结构体的定义
使用type和struct关键字定义结构体,具体如下:
type 类型名 struct {
字段名 字段类型
字段名 字段类型
…
}
ps:
1.类型名:定义结构体的名称,在同一个包内不能重复。
2.字段名:结构体字段名。结构体中的字段名必须唯一。
3.字段类型:结构体字段的具体类型。
举例:
type person struct {
name string
city string
age int8
}
//也可以这样写
type person struct {
name, ciry string
age int8
}
上面定义了一个person的自定义类型,有name、city、age三个字段,表示姓名、城市和年龄。基础数据类型是用来描述一个值的,而结构体是用来描述一组值的。比如一个人有名字、年龄和居住城市等,其本质是一种聚合型的数据类型。
2、结构体实例化
只有当结构体实例化时,才会真正地分配内存。
2.1 普通实例化
结构体本身也是一种类型,所以同样可以使用var关键字声明结构体。
type Person struct {
name, city string
age int
}
func main() {
var p1 Person //声明结构体
p1.name = "张三" //访问结构体成员
p1.age = 22
p1.city = "北京"
fmt.Println(p1.city)
fmt.Println(p1)
}
通过 . 访问结构体的字段(成员变量),如p1.name和p1.age 等
2.2 new实例化
Go 语言还可以使用 new 关键字对类型(包括结构体、整型、浮点数、字符串等)进行实例化,结构体在实例化后会形成指针类型的结构体。
使用 new 的格式: res := new(T)
ps: T 为类型,可以是结构体、整型、字符串等。 res : T 类型被实例化后保存到该变量中, res 的类型为 *T ,属于指针。
Go语言支持对结构体指针直接使用 . 来访问结构体的成员。
//也可以这样写
type person struct {
name, ciry string
age int8
}
func main() {
p1 := new(Person)
p1.name = "张三"
p1.age = 22
p1.city = "北京"
fmt.Println(p1.city)
fmt.Println(p1)
}
经过 new 实例化的结构体实例在成员赋值上与普通实例化的写法一致。从打印的结果中可以看出p1是一个结构体指针。
2.3 取地址实例化
Go 语言中,对结构体进行 & 取地址操作视为对该类型进行一次 new 的实例化操作,格式如下: res := &T{}
其中, T : 表示结构体类型。 res :为结构体的实例,类型为 *T ,是指针类型
type Person struct {
name, city string
age int
}
func main() {
p1 := new(Person)
p1.name = "张三"
p1.age = 22
p1.city = "北京"
p2 := &Person{}
p2.name = "李四"
p2.age = 28
p2.city = "上海"
fmt.Println(p1)
fmt.Println(p2)
}
3、结构体初始化
3.1 键值对初始化
结构体可使用“键值对”(Key value)初始化字段,每个“键”对应结构体中的一个字段,键的“值”对应字段需要初始化的值。
键值对的填充是可选的,不需要初始化的字段可以不填入初始化列表。
结构体实例化后字段的默认值是字段类型的默认值,如 ,数值为 0 、字符串为 “”(空字符串)、布尔为 false 、指针为 nil 等。
type Person struct {
name, city string
age int
}
func main() {
p1 := Person{
name: "张三",
city: "北京",
age: 22,
}
p2 := &Person{
name: "李四",
}
fmt.Println(p1)
fmt.Println(p2)
}
3.2 多值列表初始化
Go 语言可以在“键值对”初始化的基础上忽略“键”,即可以使用多个值的列表初始化结构体的字段。多个值使用逗号分隔,例如:
type Person struct {
name, city string
age int
}
func main() {
p1 := Person{
"张三",
"北京",
22,
}
fmt.Println(p1)
}
使用这种方式需注意:
- 必须初始化结构体的所有字段。
- 每一个初始值的填充顺序必须与字段在结构体中的声明顺序一致。
- 键值对与值列表的初始化形式不能混用。
4、匿名结构体
定义一些临时数据结构场景下可以使用匿名结构体。
// 定义 printMsgType() 函数,参数为 msg,类型为 *struct{id int data string},
// 因为类型没有使用 type 定义,所以需要在每次用到的地方进行定义。
func printMsgType(msg *struct {
id int
data string
}) {
// 使用动词%T打印msg的类型
fmt.Printf("%T\n", msg) // *struct { id int; data string }
fmt.Println(msg)
}
func main() {
// 实例化一个匿名结构体
msg := &struct { // 定义部分
id int
data string
}{ // 值初始化部分
666,
"helloWorld",
}
printMsgType(msg)
}
5、结构体作为形参
可以将结构体类型作为参数传递给函数。
func printMsg(person Person) {
fmt.Printf("age : %d\n", person.age)
fmt.Printf("name : %s\n", person.name)
fmt.Printf("city : %s\n", person.city)
}
func main() {
p1 := Person{
"小明",
"广州",
25,
}
printMsg(p1)
}