Go——结构体

news/2024/4/27 13:50:53/文章来源:https://blog.csdn.net/weixin_57023347/article/details/136971469

        Go语言中没有类的概念,也不支持类的继承等面向对象的概念。Go语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性。

一. 类型别名和自定义类型

        1.1 自定义类型

       在Go语言中有一些基本的数据类型,如string,整型,浮点型,布尔型等数据结构,Go中可以使用type关键字来自定义类型。

        自定义类型是定义了一个全新的类型。我们可以基于内置的基本类型来定义,也可以通过struct来定义。

        例如:

        通过type关键字定义,MyInt就是一种新的类型,它具有int的特性。

type MyInt int

        1.2 类型别名

        类型别名是Go1.9版本新加的新功能。

        类型别名规定:TypeAlias只是Type的别名,本质TypeAlias和Type是同一个类型。

type TypeAlias = Type

        内置类型rune和byte就是类型的别名:

type byte = uint8
type rune = int32

        1.3 自定义类型和类型别名的区别

        自定义类和类型别名表面上看只有一个等号的差异,实际上自定义类型是新增了一个类型,而类型别名并没有新增类型。

        下面的例子表明:a的类型为main.NewInt,表示在main包下定义的NewInt类型。b的类型为int,MyInt类型只会在代码中存在,编译完成时并不会有MyInt类型。

二.结构体

        Go语言中的基础类型可以表示一些事物的基本属性,但是我们想表达一个事物的全部或者部分属性时,这时单一的基本数据类型已经无法满足需求了,Go语言提供了一种自定义数据类型,可以封装多个基本数据类型,这种数据类型叫结构体,英文名字为struct。

        Go语言通过struct来实现面对对象。

        2.1 结构体的定义

        使用type和struct关键字来定义结构体,具体代码风格为:

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

其中:

  • 类型名:标识自定义结构体名称,在同一个包内不能重复。
  • 字段名:表示结构体的字段名。结构体中的字段名必须唯一。
  • 字段类型:表示结构体字段的具体类型。

        下面定义了Person和Person1自定义类型,它们拥有name,city和age三个字段,分别表示姓名,城市和年龄。这样我们使用这个Person和Person1结构体就能够很方便的在程序中存储人的信息了。 

package maintype Person struct {name stringcity stringage  uint8
}// 同样类型的可以写在一行
type Person1 struct {name, city stringage        uint8
}

        2.2 结构体的实例化

        只有当结构体实例化时,才会正真的分配内存。也就是必须实例化后才能使用结构体字段。

        结构体本身也是一种类型,我们可以像声明内置类型一样使用var关键字声明结构体类型。

var 结构体实例 结构体类型
  • 基本实例化

        我们可以通过'.'来访问结构体字段(成员变量),例如user1.name和user1.age

package mainimport "fmt"type Person struct {name stringcity stringage  uint8
}func main() {var user1 Personuser1.name = "张三"user1.city = "上海"user1.age = 26fmt.Printf("user1 : %v\n", user1)fmt.Printf("user1 : %#v\n", user1)
}

  • 匿名结构体

        在定义一些临时数据结构等场景下还可以使用匿名结构体。

package mainimport "fmt"func main() {var user struct {name stringage  uint8}user.name = "张三"user.age = 26fmt.Printf("user : %#v\n", user)
}

        2.3 结构体指针

  • 使用new关键字

        我们可以通过new关键字对结构体进行实例化,得到的是结构体地址。

        需要注意的是在Go语言中支持对结构体指针直接使用"."来访问结构体成员这是Go语言的语法糖,实际底层是(*user).name = "开发"。不像C/C++需要使用"->"。

package mainimport "fmt"type Person struct {name stringcity stringage  uint8
}func main() {var user = new(Person)fmt.Printf("%T\n", user)fmt.Printf("user : %#v\n", user)//可以使用符号.来访问user.name = "开发"user.city = "上海"user.age = 20fmt.Printf("user : %#v\n", user)
}

  • 取结构体地址实例化

        使用&对结构体进行取地址操作相当于对结构体类型进行一次new实例化操作。

package mainimport "fmt"type Person struct {name stringcity stringage  uint8
}func main() {user := &Person{} //相当于new(Person)fmt.Printf("%T\n", user)fmt.Printf("user : %#v\n", user)user.name = "张三"user.city = "上海"user.age = 20fmt.Printf("user:%#v\n", user)
}

        2.4 结构体初始化

  • 不进行初始化,属性为默认值

  • 使用键值对进行初始化

变量:

 也可以对指针进行初始化:

  • 使用值的列表初始化

        初始化结构体时可以简写,也就是初始化的时候不写键,直接写值,但是需要注意:

  • 必须初始化结构体的所有字段
  • 初始值的填充顺序必须与字段结构体中的声明顺序一样
  • 该方式不能和键值初始化方式混用

         2.5 结构体内存布局

        结构体变量里的变量在内存中也是连续保存的。

         但是也存在内存对齐,对齐规则和C语言一样:结构体在内存中的存储(内存对齐)_结构体在内存中的存放-CSDN博客

         2.6 构造函数

        Go语言的结构体没有构造函数,但是可以自己实现。例如:下方代码就实现了Person的构造函数。因为struct是值类型,如果结构体比较复杂,值拷贝性能开销会比较大,所以构造函数返回的是结构体指针类型。

package mainimport "fmt"type Person struct {name stringcity stringage  uint8
}func newPerson(name, city string, age uint8) *Person {return &Person{name: name,city: city,age:  age,} //&底层也是使用的new,然后再赋值
}func main() {user := newPerson("张三", "上海", 20)fmt.Printf("user:%#v\n", user)
}

        2.7 方法和接收者

        Go语言的方法(Method)是一种作用于特定类型变量的函数。这种特定类型变量叫做接收者(Receiver)。接收者的概念类似于其他语言中的this或者self。

        格式:

func (接收者变量 接收者类型) 方法名 (参数列表) 返回参数{函数体
}
  • 接收者变量:接收者的参数变量名在命名时,官方建议使用接收者类型名的第一个小写字母,而不是self,this之类的命名。例如Person类型的接收者变量应该命名为p,Connector类型的接收者变量应该命名为c等。
  • 接收者类型:接收者类型和参数类似,可以是指针类型或非指针类型
  • 方法名,参数列表,返回参数:具体格式与函数定义相同。

举个例子:

        Dream是结构体Person中的方法,可以通过接收者变量访问结构中中的变量。

方法和函数的区别:函数不属于任何类型,方法属于特定类型。 

  •  指针类型的接收者

        指针类型的接收者由一个结构体的指针组成,由于指针的特性,调用方法时修改接收者指针的任意成员变量,在方法结束后,修改是有效的。这种方式就十分接近其他语言中面向对象的this或者self。

        例如:我们为Person添加一个SetAge方法,来修改实际变量年龄。

  • 值类型接收者

        当方法作用于值类型接收者时,Go语言会在代码运行时将接收者的值复制一份。在值类型接收者的方法中可以获取接收者的成员值,但是修改只是针对副本,无法修改接收者变量本身。

 什么时候使用指针类型接收者?

  • 需要修改接收者中的值
  • 接收者的拷贝代价比较大的大对象
  • 保证一致性,如果有某个方法使用指针接收者,那么其他方法也应该使用指针接收者。
  • 任意类型添加方法

        在Go语言中,接收者类型可以是任何类型,不仅仅是结构体,任何类型都可以拥有方法。

        举个例子:我们基于内置的int类型使用type关键字可以定义新的自定义类型,然后我们为自定义类型添加方法。

注意事项:非本地类型不能定义方法,也就是说我们不能给别的包的类型定义方法。

所以上面的int我们需要自定义类型为MyInt到当前包。 

         2.8 结构体的匿名字段

        结构体允许其成员字段在声明时没有字段名,而只有类型,这种没有名字的字段就称为匿名字段。

        匿名字段默认使用类型名作为字段名,结构体要求字段名称必须唯一,因此一个结构体中同类型的匿名字段只能有一个。

        2.9 嵌套结构体

        一个结构体中可以嵌套包含另一个结构体或结构体指针:

  • 嵌套匿名结构体 

        当访问结构体成员时会先在结构体中查找该字段,找不到再去匿名结构体中查找。

  •  嵌套结构体内部可能存在相同的字段名

        这个时候为了避免歧义需要指定具体的内嵌结构体的字段。

        2.10 结构体中的继承

        Go语言中使用结构体也可以实现其他编程语言中的面向对象的继承。

        实际是通过嵌套实现的。

        2.11 结构体字段的可见性

        结构体中字段大写开头表示可以公开访问,小写表示私有(仅在定义当前结构体的包中可以访问)。

        2.12 结构体于JSON序列化

        JSON是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。JSON键值对是用来保存JS对象的一种方式,键/值对组合中的键名写在前面并用双引号""包裹,使用冒号:分隔,然后紧接着值; 多个键值之间使用英文,分隔。

        注意结构体的变量名需要首字母大写才能被序列化和反序列化。

package mainimport ("encoding/json""fmt"
)type Student struct {ID     int    `json:"ID"`Gender string `json:"Gender"`Name   string `json:"Name"`
}type Class struct {//变量首字母大写才能被解析Title string     //不填json键默认变量名Stu   []*Student `json:"stu"` //序列化后的数据字段是返回指定格式的,可以小写,或随意命名
}func main() {c := Class{Title: "101",Stu:   make([]*Student, 0, 200),}for i := 0; i < 10; i++ {stu := &Student{ID:     i,Gender: "男",Name:   fmt.Sprintf("stu%02d", i),}c.Stu = append(c.Stu, stu)}// for i := 0; i < len(c.Stu); i++ {// 	fmt.Println(c.Stu[i])// }//json序列化:结构体——>JSON格式字符串data, err := json.Marshal(c)if err != nil {fmt.Println("json marshal fail", err)return}fmt.Printf("json %s\n", data)//json反序列化 键需要和结构体的键对应str := `{"title":"101","stu":[{"ID":0,"Gender":"男","Name":"stu00"},{"ID":1,"Gender":"男","Name":"stu01"},{"ID":2,"Gender":"男","Name":"stu02"},{"ID":3,"Gender":"男","Name":"stu03"},{"ID":4,"Gender":"男","Name":"stu04"},{"ID":5,"Gender":"男","Name":"stu05"},{"ID":6,"Gender":"男","Name":"stu06"},{"ID":7,"Gender":"男","Name":"stu07"},{"ID":8,"Gender":"男","Name":"stu08"},{"ID":9,"Gender":"男","Name":"stu09"}]}`c1 := &Class{}err = json.Unmarshal([]byte(str), c1)if err != nil {fmt.Println("json Unmarshal fail", err)return}fmt.Printf("%#v\n", c1)
}

         2.13 结构体标签

        Tag是结构体的元信息,可以在运行的时候通过反射的机制读取出来。

        Tag在结构体字段的后方定义,由一对反引号包裹起来,具体格式如下:

`key1:"value1" key2:"value2"`

        结构体标签由一个或者多个键值对组成。键与值使用冒号分隔,值用双引号括起来。键值对之间使用一个空格分隔。

        注意事项:为结构体编写Tag时,必须严格遵守键值对的规则。结构体标签的解析代码的容错能力很差,一旦格式写错,编译和运行都不会有任何提示,通过反射也不会取到正确的值。例如:不要在key和value之间添加空格。

        例如:我们为Student结构体的每个字段定义json序列化时使用的Tag:

         2.14 删除map类型的结构体

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_1026471.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

手机网页关键词视频爬虫采集软件可导出视频分享链接|视频无水印批量下载工具

全新音视频批量下载工具&#xff0c;为您解放视频管理烦恼&#xff01; 现如今&#xff0c;音上涌现出大量精彩的视频内容&#xff0c;但是要想高效地获取、管理和分享这些视频却是一件颇具挑战的事情。针对这一难题&#xff0c;我们自主研发了全新的音视频批量下载工具&#x…

数学建模体育建模和经济建模国防科大版

目录 6.体育中的数学建模 7.经济学问题中的数学建模 7.1.实物交换模型 7.2.边际效应 7.3.最佳消费选择模型 6.体育中的数学建模 体育科学的研究中&#xff0c;也有大量的数学建模问题&#xff0c;例如&#xff1a;棒球的最佳击球点问题、滑板滑雪赛道的设计、越野自行车比…

各种需要使用的方法-->vue/微信小程序/layui

各种需要使用的方法-->vue/微信小程序/layui 1、vue里样式不起作用的方法&#xff0c;可以通过deep穿透的方式2、 js获取本周、上周、本月、上月日期3、ArrayBuffer Blob 格式转换ArrayBuffer与Blob的区别ArrayBuffer转BlobBlob转ArrayBuffer需要借助fileReader对象 4、使用…

STM32使用滴答定时器实现delayms

在STM32上使用SysTick实现jiffies&#xff08;时间戳&#xff09;并且实现delay_ms 代码实现&#xff1a; volatile uint32_t jiffies 0; // 用于记录系统运行的jiffies数 void SysTick_Handler(void) {/* 每次SysTick中断&#xff0c;jiffies增加 */jiffies; }uint32_t tick…

如何利用生成式人工智能挑选合适的候选人?

在当今激烈的商业竞争中&#xff0c;招聘合适的人才是构建企业成功的基石。筛选和面试候选人是一个复杂且精细的过程&#xff0c;它不仅关系到职位的有效填补&#xff0c;更影响到企业的长期发展和团队建设。 选择合适候选人的重要性 选择合适的候选人就像寻找一片沙滩上的珍…

曲线生成 | 图解Reeds-Shepp曲线生成原理(附ROS C++/Python/Matlab仿真)

目录 0 专栏介绍1 什么是Reeds-Shepp曲线&#xff1f;2 Reeds-Shepp曲线的运动模式3 Reeds-Shepp曲线算法原理3.1 坐标变换3.2 时间翻转(time-flip)3.3 反射变换(reflect)3.4 后向变换(backwards) 4 仿真实现4.1 ROS C实现4.2 Python实现4.3 Matlab实现 0 专栏介绍 &#x1f5…

MP4如何把视频转MOV格式? MP4视频转MOV格式的技巧

在现代的数字媒体时代&#xff0c;视频格式转换成为了许多用户必须掌握的技能。特别是将MP4视频转换为MOV格式&#xff0c;这对于需要在Apple设备上播放或编辑视频的用户来说尤为重要。本文将详细介绍如何将MP4视频转换为MOV格式&#xff0c;帮助读者轻松应对不同设备和平台的需…

编程语言|C语言——C语言基本数据类型

前言 针对不同的数据&#xff0c;采取不同的存储方式和进行不同的处理。随着处理对象的复杂化&#xff0c;数据类型也要变得更丰富。数据类型的丰富程度直接反映了程序设计语言处理数据的能力。 C语言很重要的一个特点是它的数据类型十分丰富。因此&#xff0c;C语言程序数据处…

【Nuxt3】modules目录和nuxt3模块的简单介绍

简言 记录下nuxt3项目中module的用法 modules目录 使用 modules/ 目录在应用程序中自动注册本地模块。 这是一个很好的地方&#xff0c;可以放置您在构建应用程序时开发的任何本地nuxt模块。 nuxt模块相当于npm包&#xff0c;可以发布到npm社区中 在modules/ 目录下的本地模…

二叉树|654.最大二叉树

力扣题目地址 class Solution { public:TreeNode* constructMaximumBinaryTree(vector<int>& nums) {TreeNode* node new TreeNode(0);if (nums.size() 1) {node->val nums[0];return node;}// 找到数组中最大的值和对应的下标int maxValue 0;int maxValueIn…

Kubernetes生产集群部署指南

部署生产就绪的Kubernetes集群需要考虑到管理、负载均衡、安全、存储等很多细节&#xff0c;本文给出了一个生产就绪Kubernetes集群的完整部署流程&#xff0c;可以作为生产部署的有效参考。原文: Deploying a Production Kubernetes Cluster in 2023 — A Complete Guide Grow…

万兆车载以太网转换器 10G/2.5G多速车载以太网转换器-MC10GM

MC10GM转换器 一、产品简要分析 2.5G,5G,10G可切换万兆/多速车载以太网转换器。采用罗森博格H-MTD标准接口类型。实现将车载以太网标准2.5/5/10G BASE-T1转换为工业级2.5/5/10G 标准以太网&#xff0c;进而接入电脑或工控机. 产品实现2.5/5/10G Base-T1 和2.5/5/10G Base-R之间…

android Fragment 生命周期 方法调用顺序

文章目录 Introlog 及结论代码 Intro 界面设计&#xff1a;点击左侧按钮&#xff0c;会将右侧 青色的RightFragment 替换成 黄色的AnotherRightFragment&#xff0c;而这两个 Fragment 的生命周期方法都会打印日志。 所以只要看执行结果中的日志&#xff0c;就可以知道 Fragme…

CSS时钟案例

文章目录 1. 演示效果2. 分析思路3. 代码实现 1. 演示效果 2. 分析思路 背景是表盘&#xff0c;不用自己制作然后用CSS的定位做时针&#xff0c;分针和秒针黑点用伪元素::after生成转动用animation实现 3. 代码实现 <!DOCTYPE html> <html lang"en">&…

【详细讲解React 快速入门教程】

&#x1f525;博主&#xff1a;程序员不想YY啊&#x1f525; &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家&#x1f4ab; &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 &#x1f308;希望本文对您有所裨益&#xff0c;如有…

Python中的变量与常量

变量&#xff1a;在程序运行过程中&#xff0c;值会发生变化的量&#xff0c; 常量&#xff1a;在程序运行过程中&#xff0c;值不会发生变化的量。 无论是变量还是常量&#xff0c;在创建时都会在内存中开辟一块空间&#xff0c;用于保存它的值。 Python 中的变量不需要声明…

数据链路层协议之以太网协议

以太网协议是通过网线/光纤进行通信。这和通过wifi&#xff08;无线&#xff09;&#xff0c;通过移动流量&#xff08;4G/5G&#xff09;通信不一样。以太网&#xff0c;横跨数据链路层和物理层 一.以太网数据帧格式 包括了帧头载荷(IP数据报)帧尾。 1.目的地址 源地址 分别…

初探Flink集群【持续更新】

周末下雨&#xff0c;倒杯茶&#xff0c;在家练习Flink相关。 开发工具&#xff1a;IntelliJ Idea 第一步、创建项目 打开Idea&#xff0c;新建Maven项目&#xff0c;包和项目命名 在pom.xml 文件中添加依赖 <properties><flink.version>1.13.0</flink.vers…

【Redis主从架构。主从工作原理psync、bgsave、部分数据复制、主从复制风暴解决方案】【Redis哨兵高可用架构。sentinel】

Redis主从架构 Redis主从工作原理数据部分复制 Redis哨兵高可用架构client连接哨兵规则主节点挂了&#xff0c;集群从新选择主节点&#xff0c;并且同步给sentinel 转自图灵课堂 redis主从架构搭建&#xff0c;配置从节点步骤&#xff1a; 1、复制一份redis.conf文件2、将相关…

六大原则与设计模式

1. 六大原则 1.1 单一原则&#xff08;SRP&#xff09; 应该有且仅有一个原因引起类的变更 1. 复杂性降低&#xff0c;可读性高&#xff0c;可维护性提高 2. 变更引起的风险降低&#xff0c;变更是必不可少的&#xff0c;如果接口的单一职责做得好&#xff0c;一个接口修改…