5、结构体

一、结构体创建

  • 定义结构体
type user struct {
    
    
	id         int
	score      float32
	enrollment time.Time
	name, addr string //多个字段类型相同时可以简写到一行里
}
  • 声明和初始化结构体
func main() {
    
    
	var u user                                       //声明,会用相应类型的默认值初始化struct里的每一个字段
	u = user{
    
    }                                       //用相应类型的默认值初始化struct里的每一个字段
	u = user{
    
    id: 3, name: "zcy"}                     //赋值初始化
	u = user{
    
    4, 100.0, time.Now(), "zcy", "beijing"} //赋值初始化,可以不写字段名,但需要跟结构体定义里的字段顺序一致
}
  • 默认值初始化结构体
func main() {
    
    
	var u user
	fmt.Printf("id=%d, enrollment=%v, name=[%s], addr=[%s]\n", u.id, u.enrollment, u.name, u.addr)
	// id=0, enrollment=0001-01-01 00:00:00 +0000 UTC, name=[], addr=[]
}

二、结构体访问与修改

  • 访问与修改结构体
func main() {
    
    
	var u user
	u.enrollment = time.Now()                                                 //给结构体的成员变量赋值
	fmt.Printf("id=%d, enrollment=%v, name=%s\n", u.id, u.enrollment, u.name) //访问结构体的成员变量
	// id=0, enrollment=2023-02-14 10:25:46.006792 +0800 CST m=+0.002123701, name=
}
  • 成员方法
type user struct {
    
    
	id         int
	score      float32
	enrollment time.Time
	name, addr string //多个字段类型相同时可以简写到一行里
}

// 可以把user理解为hello函数的参数,即hello(u user, man string)
func (u user) hello(man string) {
    
    
	fmt.Println("hi " + man + ", my name is " + u.name)
}

func hello(u user, man string) {
    
    
	fmt.Println("hi " + man + ", my name is " + u.name)
}

// 函数里不需要访问user的成员,可以传匿名,甚至_也不传
func (_ user) think(man string) {
    
    
	fmt.Println("hi " + man + ", do you know my name?")
}

func main() {
    
    
	ws := user{
    
    id: 0, name: "gogo"}
	ws.hello("test")  //hi test, my name is gogo
	hello(ws, "test") //hi test, my name is gogo
}
  • 为自定义类型添加方法
type UserMap map[int]user //自定义类型
// 可以给自定义类型添加任意方法
func (um UserMap) GetUser(id int) user {
    
    
	return um[id]
}
  • 结构体的可见性
    • go语言关于可见的统一规则:大写字母开头跨package也可以访问;否则只能本package内部访问
    • 结构体名称以大写开头时,package外部可见,在此前提下,结构体中以大写开头在成员变量或成员方法在package外部也可见
  • 匿名结构体:匿名结构体通常用于只使用一次的情况
var stu struct {
    
     //声明stu是一个结构体,但这个结构体是匿名的
	Name string
	Addr string
}
stu.Name = "zcy"
stu.Addr = "bj"
  • 结构体中含有匿名成员
type Student struct {
    
    
	Id int
	string //匿名字段
	float32 //直接使用数据类型作为字段名,所以匿名字段中不能出现重复的数据类型
}
var stu = Student{
    
    Id: 1, string: "zcy", float32: 79.5}
fmt.Printf("anonymous_member string member=%s float member=%f\n", stu.string, stu.float32)   //直接使用数据类型访问匿名成员

三、结构体指针

  • 创建结构体指针
func main() {
    
    
	var u User
	user := &u    //通过取址符&得到指针
	user = &User{
    
     //直接创建结构体指针
		id: 3, name: "zcy", addr: "beijing",
	}
	user = new(User) //通过new()函数实体化一个结构体,并返回其指针
}
  • 构造函数:返回指针是为了避免值拷贝
func NewUser(id int, name string) *User {
    
    
	return &User{
    
    
		Id:    id,
		Name:  name,
		addr:  "China",
		Score: 59,
	}
}
  • 方法接收指针
// user传的是值,即传的是整个结构体的拷贝;在函数里修改结构体不会影响原来的结构体
func hello(u user, man string) {
    
    
	u.name = "杰克"
	fmt.Println("hi " + man + ", my name is " + u.name)
}

// 传的是user指针,在函数里修改user的成员会影响原来的结构体
func hello2(u *user, man string) {
    
    
	u.name = "杰克"
	fmt.Println("hi " + man + ", my name is " + u.name)
}

// 把user理解为hello()的参数,即hello(u user, man string)
func (u user) hello(man string) {
    
    
	u.name = "杰克"
	fmt.Println("hi " + man + ", my name is " + u.name)
}

// 可以理解为hello2(u *user, man string)
func (u *user) hello2(man string) {
    
    
	u.name = "杰克"
	fmt.Println("hi " + man + ", my name is " + u.name)
}

四、结构体嵌套

  • 结构体嵌套
type user struct {
    
    
    name string
    sex byte
}
type paper struct {
    
    
    name string
    auther user //结构体嵌套
}
p := new(paper)
p.name = "论文标题"
p.auther.name = "作者姓名"
p.auther.sex = 0

type vedio struct {
    
    
    length int
    name string
    user//匿名字段,可用数据类型当字段名
}
  • 结构体嵌套时字段名冲突的问题
func main() {
    
    
	v := new(vedio)
	v.length = 13
	v.name = "视频名称"
	v.user.sex = 0 //通过字段名逐级访问
	v.sex = 0 //对于匿名字段也可以跳过中间字段名,直接访问内部的字段名
	v.user.name = "作者姓名" //由于内部、外部结构体都有name这个字段,名字冲突了,所以需要指定中间字段名
}

五、深拷贝与浅拷贝

  • 深拷贝,拷贝的是值:深拷贝开辟了新的内存空间,修改操作不影响原先的内存
    在这里插入图片描述
type User struct {
    
    
	Name string
}
type Vedio struct {
    
    
	Length int
	Author User
}

func main() {
    
    
	vedio1 := Vedio{
    
    11, User{
    
    "小明"}}
	vedio2 := vedio1

	vedio1.Author.Name = "小红"
	fmt.Println(vedio1) //{11 {小红}}
	fmt.Println(vedio2) //{11 {小明}}

}
  • 浅拷贝,拷贝的是指针:浅拷贝指向的还是原来的内存空间,修改操作直接作用在原内存空间上
    在这里插入图片描述
type User struct {
    
    
	Name string
}
type Vedio struct {
    
    
	Length int
	Author *User
}

func main() {
    
    
	vedio1 := Vedio{
    
    11, &User{
    
    "小明"}}
	vedio2 := vedio1

	vedio1.Author.Name = "小红"
	fmt.Println(vedio1.Author.Name) //小红
	fmt.Println(vedio2.Author.Name) //小红

}

  • slice传参,对sclice的3个字段进行了拷贝,拷贝的是底层数组的指针,所以修改底层数组的元素会反应到原数组上
type Student struct {
    
    
	Name string
	string
	int
}

func updateSlice1(arr *[]Student) {
    
    
	(*arr)[0].Name = "789"
}

func updateSlice2(arr []Student) {
    
    
	arr[0].Name = "789"
}

func updateSlice3(arr []*Student) {
    
    
	arr[0].Name = "789"
}

func main() {
    
    
	arr := []Student{
    
    {
    
    Name: "zcy", string: "bj", int: 18}}
	updateSlice1(&arr)
	fmt.Println(arr[0].Name) //789

	brr := []Student{
    
    {
    
    Name: "zcy", string: "bj", int: 18}}
	updateSlice2(brr)
	fmt.Println(brr[0].Name) //789

	crr := []*Student{
    
    {
    
    Name: "zcy", string: "bj", int: 18}}
	updateSlice3(crr)
	fmt.Println(crr[0].Name) //789

}

猜你喜欢

转载自blog.csdn.net/qq23001186/article/details/129022282