Go语言学习笔记-Go语言结构体

Go语言结构体

1. 结构体创建、访问与修改

1.1 定义结构体

//定义user结构体
type user struct {
    id int
    score float32
    enrollment time.Time
    name, addr string //多个字段类型相同时可以简写到一行里
}

1.2 声明和初始化结构体

var u user //声明,会用相应类型的默认值初始化struct里的每一个字段
u = user{} //用相应类型的默认值初始化struct里的每一个字段
u = user{id: 3, name: "xiaoming"} //赋值初始化
u = user{4, 100.0, time.Now(), "xiaoming", "beijing"} //赋值初始化,可以不写字段名,但需要跟结构体定义里的字段顺序一致

1.3 访问与修改结构体

u.enrollment = time.Now() //给结构体的成员变量赋值
fmt.Printf("id=%d, enrollment=%v, name=%s\n", u.id, u.enrollment, u.name)//访问结构体的成员变量

1.4 成员函数(方法)

//可以把user理解为hello函数的参数,即hello(u user, man string)
func (u user) hello(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?")
}

1.5 为自定义类型添加方法

type UserMap map[int]User //自定义类型
//可以给自定义类型添加任意方法
func (um UserMap) GetUser(id int) User {
    return um[id]
}

结构体的可见性:

  • go语言关于可见的统一规则:大写字母开头跨package也可以访问;否则只能本package内部访问。
  • 结构体名称以大写开头时,package外部可见,在此前提下,结构体中以大写开头在成员变量或成员方法在package外部也可见。

1.6 匿名结构体

var stu struct { //声明stu是一个结构体,但这个结构体是匿名的
	Name string
	Addr string
}
stu.Name = "zcy"
stu.Addr = "bj"

匿名结构体通常用于只使用一次的情况。

1.7 结构体中含有匿名成员

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)   //直接使用数据类型访问匿名成员

2. 结构体指针

2.1 创建结构体指针

var u User
user := &u //通过取址符&得到指针

user = &User{ //直接创建结构体指针
    Id: 3, Name: "zcy", addr: "beijing",
}

user = new(User) //通过new()函数实体化一个结构体,并返回其指针

构造函数(go语言中实际是没有构造函数的)

//构造函数。返回指针是为了避免值拷贝
func NewUser(id int, name string) *User {
	return &User{
		Id: id,
		Name: name,
		addr: "China",
		Score: 59,
	}
}

2.2 方法接收指针

//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)
}

3. 结构体嵌套

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//匿名字段,可用数据类型当字段名
}

结构体嵌套时字段名冲突的问题

v := new(vedio)
v.length = 13
v.name = "视频名称"
v.user.sex = 0 //通过字段名逐级访问
v.sex = 0 //对于匿名字段也可以跳过中间字段名,直接访问内部的字段名
v.user.name = "作者姓名" //由于内部、外部结构体都有name这个字段,名字冲突了,所以需要指定中间字段名

4. 深拷贝与浅拷贝

type User struct {
	Name string
}
type Vedio struct {
	Length int
	Author User
}

Go语言里的赋值都会发生值拷贝。

在这里插入图片描述

type User struct {
	Name string
}
type Vedio struct {
	Length int
	Author *User
}

在这里插入图片描述

  • 深拷贝,拷贝的是值,比如Vedio.Length。
  • 浅拷贝,拷贝的是指针,比如Vedio.Author。
  • 深拷贝开辟了新的内存空间,修改操作不影响原先的内存。
  • 浅拷贝指向的还是原来的内存空间,修改操作直接作用在原内存空间上。

结构体slice传参

传slice,对sclice的3个字段进行了拷贝,拷贝的是底层数组的指针,所以修改底层数组的元素会反应到原数组上。

users := []User{{Name: "康熙"}}
func update_users(users []User) {
    users[0].Name = "光绪"
}

本次课程演示代码

//main.go
package main

import struct2 "week03/struct"

//type User struct {
//	Name string
//}
//
//func update_users(users []*User) {
//	users[0].Name = "光绪"
//}

func main() {
	//struct2.Init_struct()
	//struct2.TestSelftype()
	//b := struct2.Bird{}
	//b.Walk()
	struct2.TestStructPoint()
	//users := []User{{Name: "康熙"}, {Name: "小明"}} //光绪
	//a := User{Name: "康熙"}
	//b := User{Name: "小明"}
	//users := []*User{&a, &b} //发生了拷贝
	//update_users(users)
	//fmt.Println(users[0].Name) //光绪
	//fmt.Println(a.Name)        //康熙
}

//basic.go
package struct2

import "fmt"

type student struct {
	Id            int
	Name, address string
}

func (_ student) Walk() {
	fmt.Println("runing")
}

type Bird struct{}

func (Bird) Walk() {
	fmt.Println("fly")
}

func (a student) sing(man string) {
	fmt.Println("hello " + man + " " + a.address)
}

func Init_struct() {
	var a student
	fmt.Printf("%d %s %s\n", a.Id, a.Name, a.address) //0
	a = student{}
	fmt.Printf("%d %s %s\n", a.Id, a.Name, a.address) //0
	a = student{Id: 4}
	fmt.Printf("%d %s %s\n", a.Id, a.Name, a.address) //4
	a.Id = 7
	a.Name = "xiaoming"
	fmt.Printf("%d %s %s\n", a.Id, a.Name, a.address) //7  xiaoming
}

type A struct {
	Id int
}

var ccc struct {
	Id   int
	Name string
}

func f() {
	var sss A
	fmt.Println(sss.Id)
	var ddd A
	fmt.Println(ddd.Id)

	fmt.Println(ccc.Id)
}

//sp.go
package struct2

import "fmt"

func hello1(u student) {
	u.Id = 888
	fmt.Println(u.Id) //888
}

func hello2(u *student) {
	u.Id = 888
	fmt.Println(u.Id) //888
}

func (u student) hello1() {
	u.Id = 888
	fmt.Println(u.Id) //888
}

func (u *student) hello2() {
	u.Id = 888
	fmt.Println(u.Id) //888
}

func TestStructPoint() {
	var s student //s.Id=0
	//hello1(s)
	s.hello1()
	fmt.Println(s.Id) //0

	//hello2(&s)
	s.hello2()
	fmt.Println(s.Id) //888
}

//self_type.go
package struct2

import (
	"fmt"
)

type AAA int

func (AAA) Say() {
	fmt.Println("say")
}

func (AAA) Hello() {
	fmt.Println("hello")
}

func TestSelftype() {
	var v AAA
	v = 345
	fmt.Printf("%d\n", v)
	v.Say()
	v.Hello()
}

// 构造函数
func NewStrudent(id int) *student {
	s := student{}
	s.Id = id
	s.address = "BJ"
	s.Name = "小张"
	return &s
}

func testConstruct() {
	a := NewStrudent(100)
	fmt.Println(a.address)
}

//父类
type Animal struct {
}

//子类
type Human struct {
}

// 匿名时候
type Vedio struct {
	Name string
	student
}

func TsetNest() {
	v := Vedio{Name: "tlbb"}
	v.student = student{Id: 123, Name: "jy", address: "sh"}
	fmt.Println(v.Name)         //tlbb
	fmt.Println(v.student.Id)   //123
	fmt.Println(v.Id)           //Id和address本来是student成员,现在Vedio可以直接访问,即Vedio直接拥有了Id和address,形式上等价于Vedio继承了student
	fmt.Println(v.address)      //sh
	fmt.Println(v.student.Name) //jy
}

// 不匿名时候
//type Vedio struct {
//	Name string
//	s    student
//}
//
//func TsetNest() {
//	v := Vedio{Name: "tlbb"}
//	v.s = student{Id: 123, Name: "jy", address: "sh"}
//	fmt.Println(v.Name)      //tlbb
//	fmt.Println(v.s.Id)      //123
//	fmt.Println(v.s.Id)      //123
//	fmt.Println(v.s.address) //sh
//	fmt.Println(v.s.Name)    //jy
//}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值