当前位置: 首页 > news >正文

GO结构体

1. 结构体

Go语言可以通过自定义的方式形成新的类型,结构体就是这些类型中的一种复合类型,结构体是由零个或多个任意类型的值聚合成的实体,每个值都可以称为结构体的成员。

结构体成员也可以称为“字段”,这些字段有以下特性:

  • 字段拥有自己的类型和值;
  • 字段名必须唯一;
  • 字段的类型也可以是结构体,甚至是字段所在结构体的类型。

使用关键字 type 可以将各种基本类型定义为自定义类型,基本类型包括整型、字符串、布尔等。结构体是一种复合的基本类型,通过 type 定义为自定义类型后,使结构体更便于使用。

结构体的定义格式如下:

type 类型名 struct {字段1 字段1类型字段2 字段2类型…
}

  • 类型名:标识自定义结构体的名称,在同一个包内不能重复。
  • struct{}:表示结构体类型,type 类型名 struct{}可以理解为将 struct{} 结构体定义为类型名的类型。
  • 字段1、字段2……:表示结构体字段名,结构体中的字段名必须唯一。
  • 字段1类型、字段2类型……:表示结构体各个字段的类型。

示例:

type Point struct {X intY int
}

颜色的红、绿、蓝 3 个分量可以使用 byte 类型:

type Color struct {R, G, B byte
}

结构体的定义只是一种内存布局的描述,只有当结构体实例化时,才会真正地分配内存

1.1 实例化

实例化就是根据结构体定义的格式创建一份与格式一致的内存区域,结构体实例与实例间的内存是完全独立的。

基本的实例化形式:

结构体本身是一种类型,可以像整型、字符串等类型一样,以 var 的方式声明结构体即可完成实例化。

var ins T

1

T 为结构体类型,ins 为结构体的实例。

type Index struct {x inty int
}func main() {var myIndex Index//使用.来访问结构体的成员变量,结构体成员变量的赋值方法与普通变量一致。myIndex.y = 10myIndex.x = 20fmt.Println(myIndex) //{20 10}}
//如果不赋值 结构体中的变量会使用零值初始化
type Point struct {X intY int
}
func main() {//可以使用var p = Point{X: 1,Y: 2,}var p = Point{1,2,}fmt.Printf("%v,x=%d,y=%d",p,p.X,p.Y )
}

创建指针类型的结构体:

Go语言中,还可以使用 new 关键字对类型(包括结构体、整型、浮点数、字符串等)进行实例化,结构体在实例化后会形成指针类型的结构体。

ins := new(T)

1

  • T 为类型,可以是结构体、整型、字符串等。
  • ins:T 类型被实例化后保存到 ins 变量中,ins 的类型为 *T,属于指针。

下面的例子定义了一个玩家(Player)的结构,玩家拥有名字、生命值和魔法值:

	type Player struct {name  stringhp    intpower int}play := new(Player)play.power = 10play.name = "小米"play.hp = 150fmt.Println(*play)  //{小米 150 10}

取结构体的地址实例化:

在Go语言中,对结构体进行&取地址操作时,视为对该类型进行一次 new 的实例化操作,取地址格式如下:

ins := &T{}

其中:

  • T 表示结构体类型。
  • ins 为结构体的实例,类型为 *T,是指针类型。
type Commend struct {Name    stringVar     *intCommend string
}func newCommend(name string, Var *int, commend string) *Commend {return &Commend{name,Var,commend,}
}var version = 1func main() {m := newCommend("lct", &version, "test")fmt.Println(*m)  //{lct 0x5d4318 test}
}

1.2 匿名结构体

匿名结构体没有类型名称,无须通过 type 关键字定义就可以直接使用。

ins := struct {// 匿名结构体字段定义字段1 字段类型1字段2 字段类型2…
}{// 字段值初始化初始化字段1: 字段1的值,初始化字段2: 字段2的值,…
}

  • 字段1、字段2……:结构体定义的字段名。
  • 初始化字段1、初始化字段2……:结构体初始化时的字段名,可选择性地对字段初始化。
  • 字段类型1、字段类型2……:结构体定义字段的类型。
  • 字段1的值、字段2的值……:结构体初始化字段的初始值。

// 打印消息类型, 传入匿名结构体
func printMsg(msg *struct {id   intdata string
}) {fmt.Printf("type :%T,msg:%v", msg, msg)
}func main() {msg := &struct {id   intdata string}{21,"hello",}printMsg(msg) //type :*struct { id int; data string },msg:&{21 hello}
}

2. 方法

在Go语言中,结构体就像是类的一种简化形式,那么类的方法在哪里呢?

在Go语言中有一个概念,它和方法有着同样的名字,并且大体上意思相同,Go 方法是作用在接收器(receiver)上的一个函数,接收器是某种类型的变量,因此方法是一种特殊类型的函数。

接收器类型可以是(几乎)任何类型,不仅仅是结构体类型,任何类型都可以有方法,甚至可以是函数类型,可以是 int、bool、string 或数组的别名类型,但是接收器不能是一个接口类型,因为接口是一个抽象定义,而方法却是具体实现,如果这样做了就会引发一个编译错误invalid receiver type…

接收器也不能是一个指针类型,但是它可以是任何其他允许类型的指针。

一个类型加上它的方法等价于面向对象中的一个类

在Go语言中,类型的代码和绑定在它上面的方法的代码可以不放置在一起,它们可以存在不同的源文件中,唯一的要求是它们必须是同一个包的。

类型 T(或 T)上的所有方法的集合叫做类型 T(或 T)的方法集。

在面向对象的语言中,类拥有的方法一般被理解为类可以做的事情。在Go语言中“方法”的概念与其他语言一致,只是Go语言建立的“接收器”强调方法的作用对象是接收器,也就是类实例,而函数没有作用对象。

为结构体添加方法:

需求:将物品放入背包

面向对象的写法:

将背包做为一个对象,将物品放入背包的过程作为“方法”

type Bag struct {items []int
}func (b *Bag) Insert(item int) {b.items = append(b.items, item)
}func main() {var bag Bagbag.Insert(10)fmt.Println(bag.items) //[10]
}

(b*Bag) 表示接收器,即 Insert 作用的对象实例。每个方法只能有一个接收器

2.1 接收器

接收器的格式如下:

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

接收器根据接收器的类型可以分为指针接收器、非指针接收器,两种接收器在使用时会产生不同的效果,根据效果的不同,两种接收器会被用于不同性能和功能要求的代码中。

指针类型的接收器:

指针类型的接收器由一个结构体的指针组成,更接近于面向对象中的 this 或者 self。

由于指针的特性,调用方法时,修改接收器指针的任意成员变量,在方法结束后,修改都是有效的。

示例:

使用结构体定义一个属性(Property),为属性添加 SetValue() 方法以封装设置属性的过程,通过属性的 Value() 方法可以重新获得属性的数值,使用属性时,通过 SetValue() 方法的调用,可以达成修改属性值的效果:

type Property struct {val int
}// set val
func (p *Property) setVal(val int) {p.val = val
}//get valfunc (p *Property) getVal() int {return p.val
}func main() {p := new(Property)p.setVal(20)fmt.Println(p.getVal()) //20
}

非指针类型的接收器:

当方法作用于非指针接收器时,Go语言会在代码运行时将接收器的值复制一份,在非指针接收器的方法中可以获取接收器的成员值,但修改后无效。

点(Point)使用结构体描述时,为点添加 Add() 方法,这个方法不能修改 Point 的成员 X、Y 变量,而是在计算后返回新的 Point 对象,Point 属于小内存对象,在函数返回值的复制过程中可以极大地提高代码运行效率:

package main
import ("fmt"
)
// 定义点结构
type Point struct {X intY int
}
// 非指针接收器的加方法
func (p Point) Add(other Point) Point {// 成员值与参数相加后返回新的结构return Point{p.X + other.X, p.Y + other.Y}
}
func main() {// 初始化点p1 := Point{1, 1}p2 := Point{2, 2}// 与另外一个点相加result := p1.Add(p2)// 输出结果fmt.Println(result)
}

在计算机中,小对象由于值复制时的速度较快,所以适合使用非指针接收器,大对象因为复制性能较低,适合使用指针接收器,在接收器和参数间传递时不进行复制,只是传递指针

4. 给任意类型添加方法

Go语言可以对任何类型添加方法,给一种类型添加方法就像给结构体添加方法一样,因为结构体也是一种类型。

为基本类型添加方法:

在Go语言中,使用 type 关键字可以定义出新的自定义类型,之后就可以为自定义类型添加各种方法了。我们习惯于使用面向过程的方式判断一个值是否为 0,例如:

if  v == 0 {// v等于0
}

如果将 v 当做整型对象,那么判断 v 值就可以增加一个 IsZero() 方法,通过这个方法就可以判断 v 值是否为 0,例如:

if  v.IsZero() {// v等于0
}

为基本类型添加方法的详细实现流程如下:

package main
import ("fmt"
)
// 将int定义为MyInt类型
type MyInt int
// 为MyInt添加IsZero()方法
func (m MyInt) IsZero() bool {return m == 0
}
// 为MyInt添加Add()方法
func (m MyInt) Add(other int) int {return other + int(m)
}
func main() {var b MyIntfmt.Println(b.IsZero())b = 1fmt.Println(b.Add(2))
}

5. 匿名字段

结构体可以包含一个或多个匿名(或内嵌)字段,即这些字段没有显式的名字,只有字段的类型是必须的,此时类型也就是字段的名字。

匿名字段本身可以是一个结构体类型,即结构体可以包含内嵌结构体。

Go语言中的继承是通过内嵌或组合来实现的,所以可以说,在Go语言中,相比较于继承,组合更受青睐。


type User struct {id   intname string
}type Manager struct {User
}func (u *User) ToString() string {return fmt.Sprintf("User:%p,%+v", u, u)
}func main() {m := Manager{User{1, "lct"},}fmt.Printf("manger:%p\n", &m) //manger:0xc000094030fmt.Println(m.ToString())  //User:0xc000094030,&{id:1 name:lct}
}

有点类似于重写

type User struct {id   intname string
}type Manager struct {Usertitle string
}func (u *User) ToString() string {return fmt.Sprintf("User:%p,%+v", u, u)
}func (m *Manager) ToString() string {return fmt.Sprintf("Manger:%p,%+v", m, m)
}func main() {m := Manager{User{1,"lct",}, "hahah"}fmt.Println(m.ToString()) //Manger:0xc00001a0f0,&{User:{id:1 name:lct} title:hahah}fmt.Println(m.User.ToString())  //User:0xc00001a0f0,&{id:1 name:lct}}

相关文章:

GO结构体

1. 结构体 Go语言可以通过自定义的方式形成新的类型,结构体就是这些类型中的一种复合类型,结构体是由零个或多个任意类型的值聚合成的实体,每个值都可以称为结构体的成员。 结构体成员也可以称为“字段”,这些字段有以下特性&am…...

芯科科技为全球首批原生支持Matter-over-Thread的智能锁提供强大助力,推动Matter加速成为主流技术

智能锁领域的先锋企业U-tec和Nuki选择芯科科技解决方案,成为Matter-over-Thread应用的领先者 致力于以安全、智能无线连接技术,建立更互联世界的全球领导厂商Silicon Labs(亦称“芯科科技”,NASDAQ:SLAB)今…...

面试数据库篇(mysql)- 06覆盖索引

原理 覆盖索引是指查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到 。 id name gender createdate 2 Arm...

[伴学笔记]01-操作系统概述 [南京大学2024操作系统]

文章目录 前言jyy:01-操作系统概述 [南京大学2024操作系统]为什么要学操作系统?学习操作系统能得到什么? 什么是操作系统?想要明白什么是操作系统:时间线:1940s1950s-1960s1960-1970s年代. 信息来源: 前言 督促自己,同时分享所得,阅读完本篇大约需要10分钟,希望为朋友的技术…...

c++二叉树

二叉树进阶 1.二叉搜索树(binary search tree) ​ 二叉搜索树天然就适合查找,对于满二叉树或者完全二叉树,最多搜索lgn次(就像是有序数组二分查找,每次搜索都会减少范围),极端情况简化成单链表就要走n次,即要走高度次…...

第19章-IPv6基础

1. IPv4的缺陷 2. IPv6的优势 3. 地址格式 3.1 格式 3.2 长度 4. 地址书写压缩 4.1 段内前导0压缩 4.2 全0段压缩 4.3 例子1 4.4 例子 5. 网段划分 5.1 前缀 5.2 接口标识符 5.3 前缀长度 5.4 地址规模分类 6. 地址分类 6.1 单播地址 6.2 组播地址 6.3 任播地址 6.4 例子 …...

浅谈人才招聘APP开发的解决方案

随着企业竞争加剧,高效、精准地招聘人才成为企业持续发展的关键。人才招聘系统能够简化招聘流程,提高效率,确保企业快速找到合适人才。同时,通过智能匹配和数据分析,提升招聘质量,优化候选人体验。因此&…...

大语言模型LLM推理加速:Hugging Face Transformers优化LLM推理技术(LLM系列12)

文章目录 大语言模型LLM推理加速:Hugging Face Transformers优化LLM推理技术(LLM系列12)引言Hugging Face Transformers库的推理优化基础模型级别的推理加速策略高级推理技术探索硬件加速与基础设施适配案例研究与性能提升效果展示结论与未来展望大语言模型LLM推理加速:Hug…...

JVM 第四部分—垃圾回收相关概念 2

System.gc() 在默认情况下,通过System.gc()或者Runtime.getRuntime().gc()的调用,会显式触发Full GC,同时对老年代和新生代进行回收,尝试释放被丢弃对象占用的内存 然而System.gc()调用附带一个免责声明,无法保证对垃…...

tritonserver学习之八:redis_caches实践

tritonserver学习之一:triton使用流程 tritonserver学习之二:tritonserver编译 tritonserver学习之三:tritonserver运行流程 tritonserver学习之四:命令行解析 tritonserver学习之五:backend实现机制 tritonserv…...

2024有哪些免费的mac苹果电脑深度清理工具?CleanMyMac X

苹果电脑用户们,你们是否经常感到你们的Mac变得不再像刚拆封时那样迅速、流畅?可能是时候对你的苹果电脑进行一次深度清理了。在这个时刻,拥有一些高效的深度清理工具就显得尤为重要。今天,我将介绍几款优秀的苹果电脑深度清理工具…...

UE5中实现后处理深度描边

后处理深度描边可以通过取得边缘深度变化大的区域进行描边,一方面可以用来做角色的等距内描边,避免了菲尼尔边缘光不整齐的问题,另一方面可以结合场景扫描等特效使用,达到更丰富的效果: 后来解决了开启TAA十字线和锯齿…...

Java面试值之集合

集合 1.HashMap底层?扩容机制?1.7-1.8的升级?2.HashMap的长度为什么是2的幂次方?3.HashMap 插入1.7和1.8的区别?4.什么是红黑树?O(logn)5.HashMap为什么会使用红黑树?6.ArrayList底层?扩容机制?7.LinkedList底层?扩容机制?8.ArrayList可以序列化,但是为什么不直接序…...

React之组件定义和事件处理

一、组件的分类 在react中,组件分为函数组件和class组件,也就是无状态组件和有状态组件。 * 更过时候我们应该区别使用无状态组件,因为如果有状态组件会触发生命周期所对应的一些函数 * 一旦触发他生命周期的函数,它就会影响当前项…...

LeetCode -55 跳跃游戏

LeetCode -55 跳跃游戏 给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。…...

Android和Linux的嵌入式开发差异

最近开始投入Android的怀抱。说来惭愧,08年就听说这东西,当时也有同事投入去看,因为恶心Java,始终对这玩意无感,没想到现在不会这个嵌入式都快要没法搞了。为了不中年失业,所以只能回过头又来学。 首先还是…...

关于Node.js异常处理的教程

在Node.js开发中,异常处理是非常重要的一部分。良好的异常处理可以帮助我们及时发现和解决问题,提高系统的稳定性和可靠性。本教程将向您介绍Node.js中异常处理的最佳实践和策略。 1. 使用try-catch捕获同步异常 在Node.js中,可以使用try-c…...

13. Springboot集成Protobuf

目录 1、前言 2、Protobuf简介 2.1、核心思想 2.2、Protobuf是如何工作的? 2.3、如何使用 Protoc 生成代码? 3、Springboot集成 3.1、引入依赖 3.2、定义Proto文件 3.3、Protobuf生成Java代码 3.4、配置Protobuf的序列化和反序列化 3.5、定义…...

Spring: Springboot 框架集成不同版本的spring redis

文章目录 一、集成不同版本的spring redis1、Spring Data Redis 1.x:2、Spring Data Redis 2.x:3、Spring Data Redis 3.x(Spring Boot 2.x): 二、springboot集成Spring Data Redis 2.x1、首先,确保在 pom.…...

学习JAVA的第八天(基础)

目录 多态 前提 形式 测试类 调用成员的特点 优势 劣势 包 注意事项: final关键字 常量 命名规范: 注意事项: 权限修饰符 分类 代码块 局部代码块 构造代码块 静态代码块 抽象类 抽象类: 定义格式 抽象…...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...

Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换

目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...

基于Java+VUE+MariaDB实现(Web)仿小米商城

仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意:运行前…...

【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案

目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...

HubSpot推出与ChatGPT的深度集成引发兴奋与担忧

上周三,HubSpot宣布已构建与ChatGPT的深度集成,这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋,但同时也存在一些关于数据安全的担忧。 许多网络声音声称,这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...