Go语言学习之路-9-结构体

什么是结构体

回顾下slice和map他们都是单类型的


func main() {
// 切片或者数组的类型只能存一种
s1 := []int{0, 1, 2, 3, 4, 5}
// map也是同样它的这个类型的值也只能是单类型的
m1 := map[string]string{"name": "eson", "addr": "hebei"}

fmt.Println(s1, m1)
}

那如果想存储多种类型怎么办?使用结构体:struct


// Person struce save person property
type Person struct {
name string
age int
}

func main() {
p1 := Person{name: "eric", age: 18}
fmt.Printf("%v\n", p1)
}

总结下:

结构体是一组数据,它是一个复合类型(每个数据有自己的类型)

自定义类型&类型别名

除了标准的:字符串、数字、小数、布尔值我们可以通过type关键字自定义类型

// PersonAge 自定义一个类型它有uint8的所有特性
type PersonAge uint8

类型别名go1.9版本之后的新功能

package main

import "fmt"

// NewAge 自定义类型
type NewAge uint

// PersonAge go1.9之后引用了类型别名
// 类型别名规定:TypeAlias只是Type的别名,本质上TypeAlias与Type是同一个类型。
type PersonAge = uint8

func main() {
var a1 NewAge
var a2 PersonAge

fmt.Printf("自定义类型: %T\n", a1) // 自定义类型: main.NewAge
fmt.Printf("类型的别名: %T\n", a2) // 类型的别名: uint8
}

类型别名规定:TypeAlias只是Type的别名,本质上TypeAlias与Type是同一个类型。好比一个人本身有中文名字又启用了一个英文名字,这个应为名字指向也是同一个人

区别:

自定义类型是一个独立的数据类型,但是类型别名他的类型还是它指向的数据类型

使用结构体

定义结构体

type 类型名 struct {
    字段名 字段类型
    字段名 字段类型
    …
}

解释:

  • 类型名:标识自定义结构体的名称,在同一个包内不能重复
  • 字段名:标识结构体字段名。同一个结构体内的字段名必须唯一
  • 字段类型:标识结构体字段的具体类型
type Person struct {
	name string
	age  uint
}

声明使用

标准声明方式

func main() {
	// 标准声明方式
        // 当我们定义了一个变量后默认就使用了这个结构体的零值
	var p1 Person
	fmt.Printf("%v\n", p1)
	p1.name = "eric"
	fmt.Printf("%v\n", p1)
}

实例化指针

func main() {
	// p1 := new(Person) 
	// 或者采用
	p1 := &Person{}
	fmt.Printf("%v\n", p1)
}

new或者取址符会返回一个指针类型的结构体,什么使用指针类型的结构体呢?

  • 结构体很大的时候不希望每次使用的时候都COPY一份内存数据

实例化先声明一个变量在赋值(没有初始化实例化一般都会使用零值),初始化是在声明的时候就赋值

初始化声明(常用)

package main

import "fmt"

type person struct {
	name string
	age  int
}

func main() {
	// 键值对初始化
	p1 := person{name: "eson", age: 18}

	// 列表初始化
	p2 := person{"eric", 18}

	// 指针初始化(&或new)
	p3 := &person{name: "fire", age: 18}

	fmt.Printf("%v,%v,%v", p1, p2, p3)
}

匿名结构体

在一些需要临时使用一个结构体的场景的时候,可以使用匿名结构体

package main

import "fmt"

func main() {
	// 匿名结构体
	var user struct {
		name string
		age  int
	}
	user.name = "eson"
	user.age = 18
	// user的类型是: struct { name string; age int }
	fmt.Printf("user的类型是: %T\n", user)
	// user的值:{eson 18}
	fmt.Printf("user的值:%v\n", user)
}

结构体的指针优化

看下面的例子

package main

import "fmt"

type person struct {
	name string
	age  int
}

func main() {
	p1 := &person{name: "John", age: 18} // 初始化一个person的结构体指针变量
	// 当我们使用的时候怎么用?
}

如下方式调用,是不是怪怪的?

package main

import "fmt"

type person struct {
	name string
	age  int
}

func main() {
	p1 := &person{} // 初始化一个person的结构体指针变量
	// 当我们使用的时候怎么用?
	(*p1).name = "John"
	(*p1).age = 18
	fmt.Printf("%v\n", p1) // &{John 18}
}

go给我们做了一个语法糖,我们可以在调用指针类型的结构体的时候可以进行简写成如下

package main

import "fmt"

type person struct {
	name string
	age  int
}

func main() {
	p1 := &person{} // 初始化一个person的结构体指针变量
	p1.name = "John"
	p1.age = 18
	fmt.Printf("%v\n", p1)  // &{John 18} 它还是一个指针类型的
}

结构体嵌套

package main

import "fmt"

// Address 包含省份和城市
type Address struct {
	Province string
	City     string
}

// Info 包含年龄、email等信息
type Info struct {
	Age   int
	Email string
}

// 长辈
type Account struct {
	Email string
}

// Student 学生信息
type Student struct {
	Name    string
	Address Address
	Info
	Account
}

func main() {
	s1 := &Student{Name: "eson",
		Info:    Info{Age: 18, Email: "eson@gamil.com"},
		Address: Address{Province: "hb", City: "hs"},
		Account: Account{Email: "eson@gamil.com"},
	}
	fmt.Println(s1.Name)
	// 匿名字段可以直接访问
	fmt.Println(s1.Age)
	// 非匿名字段需要输入输入输入全部
	fmt.Println(s1.Address.City)
	// 如果匿名字段冲突了需要输入全部的
	fmt.Println(s1.Info.Email)
	fmt.Println(s1.Account.Email)
}

posted @ 2021-01-16 08:51  天帅  阅读(150)  评论(0编辑  收藏  举报