首页 > 其他分享 >GO语言中的结构体

GO语言中的结构体

时间:2023-10-16 10:25:35浏览次数:32  
标签:语言 float32 waiyu user student GO 结构 string name

结构体创建、访问与修改

定义结构体

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

声明和初始化结构体

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


//或者使用new,通过new()函数实体化一个结构体,并返回其指针
u:=new(user)

访问与修改结构体

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

成员方法

给结构体添加方法

//可以把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?")
}

为自定义类型添加方法

type UserMap map[int]User //自定义类型     定义了一个数据类型是map的结构体,map的值都是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)   //直接使用数据类型访问匿名成员

结构体指针

指针是在变量前加&,就是取址

解析指针中的值就用*


创建结构体指针

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


//例子
package main

import "fmt"

type User struct {
	name string
	string
	int
}

//不传指针,那么传的就是值,只是个拷贝的值
func (u User) h() {
	u.name = "qqqq"
}

//传指针,就是修改的原结构体    绝大多数时候用的都是传指针
func (u *User) h2() {
	u.name = "wwwww"
}
func (u User) NewUser(name string, city string, age int) *User {
	u.name = name
	u.string = city
	u.int = age
	return &u
}

func main() {
	user := User{"abc", "aaa", 12}
	user.h()
	fmt.Println(user.name) //abc
	user.h2()
	fmt.Println(user.name) //wwwww
	user2 := User{"cccc", "dddd", 15}
	fmt.Println(user2.name) //cccc
}

结构体嵌套

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这个字段,名字冲突了,所以需要指定中间字段名

深拷贝与浅拷贝

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,对sclice的3个字段进行了拷贝,拷贝的是底层数组的指针,所以修改底层数组的元素会反应到原数组上。

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

练习

需求:创建一个student结构体,包含姓名和语数外三门课的成绩。用一个slice容纳一个班的同学,求每位同学的平均分和整个班三门课的平均分,全班同学平均分低于60的有几位

package main

import "fmt"

//创建一个student结构体,包含姓名和语数外三门课的成绩。用一个slice容纳一个班的同学,求每位同学的平均分和整个班三门课的平均分,全班同学平均分低于60的有几位
type student struct {
	name                  string
	yunwen, shuxue, waiyu float32
	junzhi                float32
}

type class struct {
	xueshen               []*student
	yunwen, shuxue, waiyu float32
	bujige                []*student
}

func (s *student) pinjunfen() {
	s.junzhi = (s.yunwen + s.shuxue + s.waiyu) / 3.0
}
func (c *class) pinjun() {
	var sumyuwen float32 = 0.0
	var sumshuxue float32 = 0.0
	var sumwaiyu float32 = 0.0
	for _, s := range c.xueshen {
		sumyuwen += s.yunwen
		sumshuxue += s.shuxue
		sumwaiyu += s.waiyu
		s.pinjunfen()
		if s.junzhi < 60 {
			c.bujige = append(c.bujige, s)
		}
	}
	c.yunwen = sumyuwen / float32(len(c.xueshen))
	c.shuxue = sumshuxue / float32(len(c.xueshen))
	c.waiyu = sumwaiyu / float32(len(c.xueshen))
}
func main() {
	c := new(class)
	s1 := student{
		name:   "s1",
		yunwen: 12.5,
		shuxue: 60.2,
		waiyu:  44.3,
	}
	s2 := student{
		name:   "s2",
		yunwen: 60,
		shuxue: 60.2,
		waiyu:  75,
	}
	s3 := student{
		name:   "s3",
		yunwen: 50,
		shuxue: 33.6,
		waiyu:  25.3,
	}
	s4 := student{
		name:   "s4",
		yunwen: 100,
		shuxue: 82,
		waiyu:  98,
	}
	s5 := student{
		name:   "s5",
		yunwen: 88,
		shuxue: 90,
		waiyu:  60,
	}
	c.xueshen = []*student{&s1, &s2, &s3, &s4, &s5}
	c.pinjun()
	fmt.Printf("第四个学生的平均分%.2f   班级的语文平均分%.2f   班级的数学平均分%.2f   班级的外语平均分%.2f   平均分不及格的同学数%d\n", c.xueshen[3].junzhi, c.yunwen, c.shuxue, c.waiyu, len(c.bujige))
	fmt.Printf("%+v", c)
}

遇到的问题:

之前定义的xueshen是student的切片

type class struct {
	xueshen               []student
	yunwen, shuxue, waiyu float32
	bujige                []student
}

遇到的问题是,当打印平均分时,平均分显示0,表明在class中的pingjun方法中s.pinjunfen()并没有修改到原数据,只是修改的一个拷贝。

所以将这里都修改成student指针的切片,这样就可以修改到原有的数据了。

在下面给c加入数据时,传的也是地址c.xueshen = []*student{&s1, &s2, &s3, &s4, &s5}

或者

修改成,在将student加入到classxueshen之前,就让每个student自己执行一遍pingjunfen,这样,数据也能保证正常修改

package main

import "fmt"

//创建一个student结构体,包含姓名和语数外三门课的成绩。用一个slice容纳一个班的同学,求每位同学的平均分和整个班三门课的平均分,全班同学平均分低于60的有几位
type student struct {
	name                  string
	yunwen, shuxue, waiyu float32
	junzhi                float32
}

type class struct {
	xueshen               []student
	yunwen, shuxue, waiyu float32
	bujige                []student
}

func (s *student) pinjunfen() {
	s.junzhi = (s.yunwen + s.shuxue + s.waiyu) / 3.0
}
func (c *class) pinjun() {
	var sumyuwen float32 = 0.0
	var sumshuxue float32 = 0.0
	var sumwaiyu float32 = 0.0
	for _, s := range c.xueshen {
		sumyuwen += s.yunwen
		sumshuxue += s.shuxue
		sumwaiyu += s.waiyu
        //不再让遍历的时候执行pingjunfen(),而是让student自己先做一遍
		// s.pinjunfen()
		if s.junzhi < 60 {
			c.bujige = append(c.bujige, s)
		}
	}
	c.yunwen = sumyuwen / float32(len(c.xueshen))
	c.shuxue = sumshuxue / float32(len(c.xueshen))
	c.waiyu = sumwaiyu / float32(len(c.xueshen))
}
func main() {
	c := new(class)
	s1 := student{
		name:   "s1",
		yunwen: 12.5,
		shuxue: 60.2,
		waiyu:  44.3,
	}
	s2 := student{
		name:   "s2",
		yunwen: 60,
		shuxue: 60.2,
		waiyu:  75,
	}
	s3 := student{
		name:   "s3",
		yunwen: 50,
		shuxue: 33.6,
		waiyu:  25.3,
	}
	s4 := student{
		name:   "s4",
		yunwen: 100,
		shuxue: 82,
		waiyu:  98,
	}
	s5 := student{
		name:   "s5",
		yunwen: 88,
		shuxue: 90,
		waiyu:  60,
	}
    //让所有的student先自己做一遍pingjunfen(),再加到class的xueshen中
	s1.pinjunfen()
	s2.pinjunfen()
	s3.pinjunfen()
	s4.pinjunfen()
	s5.pinjunfen()
	c.xueshen = []student{s1, s2, s3, s4, s5}
	c.pinjun()
	fmt.Printf("第四个学生的平均分%.2f   班级的语文平均分%.2f   班级的数学平均分%.2f   班级的外语平均分%.2f   平均分不及格的同学数%d\n", c.xueshen[3].junzhi, c.yunwen, c.shuxue, c.waiyu, len(c.bujige))
	fmt.Printf("%+v", c)
}

标签:语言,float32,waiyu,user,student,GO,结构,string,name
From: https://www.cnblogs.com/guangdelw/p/17766778.html

相关文章

  • GO语言中面向接口编程
    接口的基本概念接口是一组行为规范的集合。typeTransporterinterface{//定义接口。通常接口名以er结尾//接口里面只定义方法,不定义变量move(srcstring,deststring)(int,error)//方法名(参数列表)返回值列表whistle(int)int//参数列表和返回值列表......
  • 轻松掌握组件启动之MongoDB(上):高可用复制集架构环境搭建
    MongoDB复制集复制集架构在生产环境中,强烈不建议使用单机版的MongoDB服务器。原因如下:单机版的MongoDB无法保证系统的可靠性。一旦进程发生故障或是服务器宕机,业务将直接不可用。此外,一旦服务器上的磁盘损坏,数据会直接丢失,而此时并没有任何副本可用。为了确保数据的高可用性和......
  • GO语言中的函数
    函数的基本形式//函数定义。a,b是形参funcargf(aint,bint){ a=a+b}varx,yint=3,6argf(x,y)//函数调用。x,y是实参形参是函数内部的局部变量,实参的值会拷贝给形参。函数定义时的第一个的大括号不能另起一行。形参可以有0个或多个。参数类型相同时可......
  • 计算机体系结构模拟器gem5
     【Gem5】gem5模拟器中三种访存模式Atomic、Timing、Functional的总结对比_空空7的博客-CSDN博客Gem5//谭邵杰的计算机奇妙旅程(ustc.edu.cn)GEM5是一款模块化的离散事件驱动全系统模拟器,由C++与python编写它结合了M5(多处理器模拟器)和GEMS(存储层次模拟器)中最优秀的部分,是......
  • Linux ls 查看目录结构与文档信息
    摘要:Linuxls命令用于列出目标目录中所有的子目录和文件,发掘并掌握ls命令及其参数设置可以驾轻就熟地管理文件,随心所欲地浏览并确定所在的位置!ls命令介绍  今天,楼兰胡杨继续跟各位猿友一起零基础学习Linux相关指令——ls,它是一条Linux必备命令。发掘并掌握ls命令常用功能,可以......
  • 树叶识别系统python+Django网页界面+TensorFlow+算法模型+数据集+图像识别分类
    一、介绍树叶识别系统。使用Python作为主要编程语言开发,通过收集常见的6中树叶('广玉兰','杜鹃','梧桐','樟叶','芭蕉','银杏')图片作为数据集,然后使用TensorFlow搭建ResNet50算法网络模型,通过对数据集进行处理后进行模型迭代训练,得到一个识别精度较高的H5模型文件。并基于Dja......
  • 14.6 Socket 应用结构体传输
    当在套接字编程中传输结构体时,可以将结构体序列化为字符串(即把结构体的所有成员打包成一个字符串),然后将字符串通过套接字传输到对端,接收方可以将字符串解析为结构体,然后使用其中的成员数据。这种方法通常被称为序列化(Serialization)和反序列化(Deserialization),本章中我们可以采用将......
  • 14.7 Socket 循环结构体传输
    在上述内容中笔者通过一个简单的案例给大家介绍了在套接字编程中如何传递结构体数据,本章将继续延申结构体传输,在某些时候例如我们需要传输一些当前系统的进程列表信息,或者是当前主机中的目录文件,此时就需要使用循环结构体传输功能,循环传输结构体的关键点在于,客户端发送结构体数据......
  • ARC167D Good Permutation 题解
    题意给定一个长度为\(N\)的排列\((P_1,P_2,\cdots,P_N)\)。称一个排列\(P\)为“好排列”当且仅当对于所有\(1\leqx\leqN\),都能通过不停地使\(x\leftarrowP_x\)将\(x\)变成\(1\)。通过最小次数操作将\(P\)变成“好排列”,每次操作为交换\(P\)中的两个数\(P_i\)......
  • 为什么Google在JSON响应中添加了`while(1);`?
    内容来自DOChttps://q.houxu6.top/?s=为什么Google在JSON响应中添加了while(1);?为什么Google在(私有)JSON响应前加上while(1);?例如,这是在Google日历中打开和关闭日历时的响应:while(1);[['u',[['smsSentFlag','false'],['hideInvitations','false......