李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
GO
正文
10.Golang结构体(一)
Leefs
2022-07-02 PM
1535℃
0条
[TOC] ### 前言 ![10.Golang结构体(一)01.jpeg](https://lilinchao.com/usr/uploads/2022/07/437599248.jpeg) ### 一、概述 **结构体(struct)** 是一种聚合的数据类型,是**由零个或多个任意类型的值聚合成的实体**。每个值称为结构体的成员。学过 C 或 C++ 的人都知道结构体,但在 Go 中,没有像 C++ 中的 `class` 类的概念,只有 `struct` 结构体的概念,所以也没有继承。 结构体成员也可以称为“字段”,这些字段有以下特性: - 字段拥有自己的类型和值; - 字段名必须唯一; - 字段的类型也可以是结构体,甚至是字段所在结构体的类型。 Go语言中通过结构体的内嵌再配合接口比面向对象具有**更高的扩展性和灵活性**。 ### 二、类型别名和自定义类型 #### 2.1 自定义类型 在Go语言中有一些基本的数据类型,如`string`、`整型`、`浮点型`、`布尔`等数据类型, Go语言中可以使用`type`关键字来定义自定义类型。 自定义类型是定义了一个全新的类型。我们可以基于内置的基本类型定义,也可以通过struct定义。 **例如**: ```go //将MyInt定义为int类型 type MyInt int ``` 通过`type`关键字的定义,`MyInt`就是一种新的类型,它具有`int`的特性。 #### 2.2 类型别名 类型别名是`Go1.9`版本添加的新功能。 类型别名规定:`TypeAlias`只是Type的别名,本质上`TypeAlias`与Type是同一个类型。 ```go type TypeAlias = Type ``` 之前见过的`rune`和`byte`就是类型别名,他们的定义如下: ```go type byte = uint8 type rune = int32 ``` #### 2.3 类型定义和类型别名的区别 类型别名与类型定义表面上看只有一个等号的差异,通过下面的这段代码来理解它们之间的区别。 ```go //类型定义 type NewInt int //类型别名 type MyInt = int func main() { var a NewInt var b MyInt fmt.Printf("type of a:%T\n", a) //type of a:main.NewInt fmt.Printf("type of b:%T\n", b) //type of b:int } ``` 结果显示a的类型是`main.NewInt`,表示main包下定义的`NewInt`类型。b的类型是`int`。 `MyInt`类型只会在代码中存在,编译完成时并不会有`MyInt`类型。 ### 三、结构体 Go语言中通过`struct`来实现面向对象。 #### 3.1 结构体的定义 使用`type`和`struct`关键字来定义结构体,具体代码格式如下: ```go type 类型名 struct { 字段名 字段类型 字段名 字段类型 … } ``` **说明** - **类型名**:标识自定义结构体的名称,在同一个包内不能重复。 - **字段名**:表示结构体字段名。结构体中的字段名必须唯一。 - **字段类型**:表示结构体字段的具体类型。 > 示例:定义一个Person(人)结构体 ```go type person struct{ name string //姓名 city string //城市 age int8 //年龄 } ``` 可以将同一类型的字段写在一行: ```go type person struct{ name,city string age int8 } ``` 通过上方代码对`person`结构体的定义,可以在程序中更加方便的表示和存储人的信息。 语言内置的基础数据类型是用来描述一个值的,而结构体是用来描述一组值的。比如一个人有名字、年龄和居住城市等,**本质上是一种聚合型的数据类型**。 #### 3.2 结构体实例化 只有当结构体实例化时,才会真正地分配内存。也就是必须实例化后才能使用结构体的字段。 结构体本身也是一种类型,我们可以像声明内置类型一样使用`var`关键字声明结构体类型。 ```go var 结构体实例 结构体类型 ``` ##### (1)基本实例化 结构体本身是一种类型,可以像整型、字符串等类型一样,以 `var` 的方式声明结构体即可完成实例化。这种用法是为了更明确地表示一个变量被设置为零值。 **示例** ```go var phone Phone //Phone为结构体类型,phone为结构体的实例 ``` > 示例:用结构体表示点(Point)结构的实例化过程 ```go type Point struct { X int Y int } func main() { var p Point p.X = 10 p.Y = 10 fmt.Printf("X = %d\n",p.X) //X = 10 fmt.Printf("Y = %d\n",p.Y) //Y = 10 } ``` 在例子中,使用`.`来访问结构体的成员变量,如`p.X`和`p.Y`等,结构体成员变量的赋值方法与普通变量一致。 与数组类型相同,结构体类型属于值类型,因此结构体类型的零值不是 `nil`,上述 `Point` 的零值就是 `Point{}`。 ##### (2)new实例化 `Go` 语言中,还可以使用 `new` 关键字对类型(包括结构体、整型、浮点数、字符串等)进行实例化,结构体在实例化后会形成指针类型的结构体。 使用 `new` 的格式如下: ```go ins := new(T) ``` **说明** - `T` 为类型,可以是结构体、整型、字符串等。 - `ins` : `T` 类型被实例化后保存到 `ins` 变量中, `ins` 的类型为 `*T` ,属于指针。 `Go` 语言可以像访问普通结构体一样使用`.`来访问结构体指针的成员。 ```go type Student struct { name string age int gender string hobby []string } func main() { stu := new(Student) stu.name = "Leefs" stu.age = 18 stu.gender = "男" stu.hobby = []string{"足球","羽毛球"} fmt.Println((*stu).name)//Leefs fmt.Println(stu.hobby) //[足球 羽毛球] fmt.Println(stu) //&{Leefs 18 男 [足球 羽毛球]} } ``` 经过 `new` 实例化的结构体实例在成员赋值上与普通实例化的写法一致。 在 `Go` 语言中,访问结构体指针的成员交量时可以继续使用 `.` 。 这是因为 `Go` 语言为了方便开发者访问结构体指针的成员交量,使用了语法糖技术,其实 `stu.name` 底层是 `(*stu).name` 。 ##### (3)取地址实例化 在 `Go` 语言中,对结构体进行 `&`取地址操作时,视为对该类型进行一次 `new` 的实例化操作,取地址格式如下: ```go ins := &T{} ``` **说明** - `T` : 表示结构体类型。 - `ins` :为结构体的实例,类型为 `*T` ,是指针类型。 **示例** ```go type student struct{ name string age int gender string hobby []string } func main() { //通过取地址实例化操作 stu := &student{} stu.name = "Jeyoo" stu.age = 20 stu.gender = "男" stu.hobby = []string{"a","b"} fmt.Println(stu.name) //Jeyoo fmt.Println(stu.age) //20 fmt.Println(stu.gender) //男 fmt.Println(stu.hobby) //[a b] } ``` 取地址实例化是最广泛的一种结构体实例化方式,可以使用构造函数封装上面的初始化过程。 ##### 构造函数 Go语言的结构体没有构造函数,我们可以自己实现。 例如,下方的代码就实现了一个`student`的构造函数。 因为`struct`是值类型,如果结构体比较复杂的话,值拷贝性能开销会比较大,所以**该构造函数返回的是结构体指针类型**。 代码如下: ```go type student struct{ name string age int gender string hobby []string } //实现一个构造函数,习惯上new加类型名 func newStudent(name string,age int,gender string,hobby []string) *student{ return &student{ name: name, age: age, gender: gender, hobby: hobby, } } func main() { hobby := []string{"a","b"} stu := newStudent("zhangsan",18,"男",hobby) fmt.Println(stu.name) //zhangsan fmt.Println(stu.age) //18 fmt.Println(stu.gender) //男 fmt.Println(stu.hobby) //[a b] } ``` #### 3.3 结构体初始化 结构体在实例化时可以直接对成员变量进行初始化,初始化有两种形式分别是以字段“键值对”形式和多个值的列表形式,**键值对形式的初始化适合选择性填充字段较多的结构体,多个值的列表形式适合填充字段较少的结构体**。 ##### (1)键值对初始化 结构体可以使用“键值对”(Key value pair)初始化字段,每个“键”(Key)对应结构体中的一个字段,键的“值”(Value)对应字段需要初始化的值。 键值对的填充是可选的,不需要初始化的字段可以不填入初始化列表中。 结构体实例化后字段的默认值是字段类型的默认值,例如 ,数值为 `0` 、字符串为 “”(空字符串)、布尔为 `false` 、指针为 `nil` 等。 **键值对初始化的格式如下:** ```go varName := structName{key1: value1, key2: value2..., keyn: valuen}// 键值之间以:分隔,键值对之间以,分隔。 ``` **示例** ```go type People struct { name string child *People } func main() { relation := &People{ name: "grandpa", child: &People{ name: "dad", child: &People{ name: "grandson", }, }, } fmt.Println(relation.name) } ``` **注意:结构体成员中只能包含结构体的指针类型,包含非结构体指针类型会引起编译错误。** #####(2) 多值列表初始化 `Go` 语言可以在“键值对”初始化的基础上忽略“键”,也就是说,可以使用多个值的列表初始化结构体的字段。多个值使用逗号分隔初始化结构体,例如: ```go varName := structName{value1, value2...valuen} ``` **使用这种格式初始化时,需要注意:** - **必须初始化结构体的所有字段**。 - **每一个初始值的填充顺序必须与字段在结构体中的声明顺序一致**。 - **键值对与值列表的初始化形式不能混用**。 **示例** ```go type student struct{ name string age int gender string hobby []string } func main() { var stu = student{ name:"张三", age:20, gender:"男", hobby:[]string{"篮球","足球","乒乓球"}, } fmt.Println(stu) //{张三 20 男 [篮球 足球 乒乓球]} //初始化 //只用值时,所有属性都要初始化,并且按照结构体顺序赋值 var b1 = student{ "Boy", 18, "男", []string{"a","b"}, } fmt.Println(b1) //{Boy 18 男 [a b]} } ``` ##### (3)空结构体 空结构体不占用空间 ```go var v struct{} //v是一个不包含任何字段的空结构体类型 fmt.Println(unsafe.Sizeof(v)) // 0 ``` 输出的空结构体类型变量的大小为 0,也就是说,空结构体类型变量的内存占用为 0。 #### 3.4 匿名结构体 匿名结构体没有类型名称,无须通过 `type` 关键字定义就可以直接使用。 ##### 匿名结构体定义和初始化 匿名结构体的初始化写法由结构体定义和键值对初始化两部分组成,结构体定义时没有结构体类型名,只有字段和类型定义,键值对初始化部分由可选的多个键值对组成,如下格式所示: ```go ins := struct { // 匿名结构体字段定义 字段1 字段类型1 字段2 字段类型2 … }{ // 字段值初始化 初始化字段1: 字段1的值, 初始化字段2: 字段2的值, … } ``` **说明** - `字段1、字段2……`:结构体定义的字段名。 - `初始化字段1、初始化字段2……`:结构体初始化时的字段名,可选择性地对字段初始化。 - `字段类型1、字段类型2……`:结构体定义字段的类型。 - `字段1的值、字段2的值……`:结构体初始化字段的初始值。 键值对初始化部分是可选的,不初始化成员时,匿名结构体的格式变为: ```go ins := struct { 字段1 字段类型1 字段2 字段类型2 … } ``` **示例** ```go func main() { var user struct{name string; age int} user.name = "Leefs" user.age = 18 fmt.Printf("%#v\n", user) //struct { name string; age int }{name:"Leefs", age:18} user2 := struct{name string; age int}{name:"Jeyoo", age:20} //struct { name string; age int }{name:"Jeyoo", age:20} fmt.Printf("%#v\n", user2) } ``` *附参考文章链接* *https://www.liwenzhou.com/posts/Go/10_struct/#autoid-2-10-2* *https://blog.csdn.net/wohu1104/article/details/99694238*
标签:
Golang基础
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:
https://lilinchao.com/archives/2212.html
上一篇
09.Golang指针介绍
下一篇
11.Golang结构体(二)
评论已关闭
栏目分类
随笔
2
Java
326
大数据
229
工具
31
其它
25
GO
47
NLP
4
标签云
设计模式
Golang基础
RSA加解密
Elastisearch
MySQL
SpringCloudAlibaba
Spark Core
VUE
栈
前端
并发编程
ajax
MyBatisX
Eclipse
序列化和反序列化
递归
Map
Yarn
LeetCode刷题
哈希表
MyBatis-Plus
数据结构和算法
微服务
Sentinel
Java工具类
MyBatis
Jquery
JavaScript
Docker
Java
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞
评论已关闭