李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
GO
正文
10.Golang结构体(一)
Leefs
2022-07-02 PM
882℃
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
43
标签云
Hive
Spark
Stream流
MySQL
Filter
VUE
JavaWEB项目搭建
Yarn
Jquery
Hadoop
链表
SpringCloud
JavaSE
Hbase
Quartz
Redis
查找
JavaWeb
Spark Streaming
国产数据库改造
哈希表
锁
Linux
Kafka
Spark RDD
数学
Zookeeper
Eclipse
栈
Netty
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞