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

简单易懂,解析Go语言中的struct结构体

目录

  • 4. struct 结构体
    • 4.1 初始化
    • 4.2 内嵌字段
    • 4.3 可见性
    • 4.4 方法与函数
      • 4.4.1 区别
      • 4.4.2 闭包
    • 4.5 Tag 字段标签
      • 4.5.1定义
      • 4.5.2 Tag规范
      • 4.5.3 Tag意义

4. struct 结构体

go的结构体类似于其他语言中的class,主要区别就是go的结构体没有继承这一概念,但可以使用类型嵌入来实现相似功能。

4.1 初始化

使用type关键字来定义一个新的类型,struct将新类型限定为结构体类型。

结构体中的字段可以为任何类型,但是包含一些特殊类型 如:接口,管道,函数,指针的时候要格外注意

//type定义一个新类型
type newInt int//type定义一个简单的结构体
type base struct{value int   
}//type定义一个复杂的结构体
type student struct {Name stringage  intc    interface{}d    func() inte    func()base     //将base类型嵌入到了student类型中
}

4.2 内嵌字段

内嵌字段大体上有两种方式:显式指定(m1)和隐式指定(m2)

  • 显式指定就相当于把目标结构体当作字段,调用时需要先调用这个字段,在调用目标结构体中的信息
  • 隐式指定相当于把目标结构体中的所有字段都在新结构体中创建了一次,并且指向嵌入结构体内部。同时创建同名嵌入结构体对象[指与base同名]
  • 显式创建同名结构体字段 ≠ 隐式指定
type base struct {Value int
}
//显式指定
type m1 struct {b base
}//隐式指定
type m2 struct {base
}//显式指定同名字段
type m3 struct {base base
}

对上述结构体进行调用:

  • 只有隐式指定直接操作被嵌入结构体内的数据;
  • 隐式指定后,直接操作嵌入结构体中的数据和通同名结构体操作作用一样
func main() {a1 := m1{}a2 := m2{}a3 := m3{}//显式指定只能通过嵌入结构体进行操作// a1.Value = 1 //a1.Value undefined (type m2 has no field or method Value)a1.b.Value = 2//隐式指定两种操作数据方法操作的是同一个变量a2.Value = 2a2.base.Value = 3fmt.Println(a2.Value) //3//显式指定同名变量 ≠ 隐式指定 // a3.Value = 3 //a3.Value undefined (type m3 has no field or method Value)a3.base.Value = 4
}

当内嵌字段中的字段与结构体中得字段同名时:

  • 直接调用时是指定当前结构体中显式定义的字段,但嵌入结构体中的字段仍可通过嵌入类型进行调用
  • 方法同理
//数据
func main() {a1 := m1{}a1.Value = "hello world"a1.base.Value = 1fmt.Println(a1)//获取a1中的所有字段类型t := reflect.TypeOf(a1)for i := 0; i < t.NumField(); i++ {field := t.Field(i)fieldType := field.Typefmt.Printf("Field: %s, Type: %s\n", field.Name, fieldType.Name())}
}type base struct {Value int
}type m1 struct {Value stringbase
}
/*
{hello world {1}}
Field: Value, Type: string
Field: base, Type: base*/
//方法
func main() {a1 := m1{}a1.test()a1.base.test()fmt.Println(a1)//获取a1中的所有字段类型t := reflect.TypeOf(a1)for i := 0; i < t.NumField(); i++ {field := t.Field(i)fieldType := field.Typefmt.Printf("Field: %s, Type: %s\n", field.Name, fieldType.Name())}
}type base struct {Value int
}func (b *base) test() {b.Value = 1
}
func (m *m1) test() {m.Value = "hello world"
}type m1 struct {Value stringbase
}
/*
{hello world {1}}
Field: Value, Type: string
Field: base, Type: base*/

4.3 可见性

  • 首字母大写表示该字段/方法/结构体为可导出的,反之为不可导出的
  • 在同一个包内,不区分是否可导出,都可访问;包外只能访问可导出的字段/方法/结构体
  • 不可导出的字段不可以进行序列化(转化为json)
  • 可通过可导出的方法去操作不可导出的字段
// test/test1.go
package testtype User struct {Name stringage  int
}func (u *User) Test() {u.Name = "hello"u.age = 18
}func (u *User) test() {u.Name = "world"u.age = 81
}type student struct {Name stringage  int
}
//main.go
package mainimport ("fmt""test/test"
)func main() {a := test.User{}//b := test.student{} // 不能在包外访问未导出结构体a.Name = "123"//a.age = 123 // 不能在包外访问未导出字段a.Test()//a.test() // 不能在包外访问未导出方法fmt.Println(a)/*{hello 18}*/
}

4.4 方法与函数

4.4.1 区别

  • 方法定义是必须有一个接收器(receiver);函数不需要
  • 大部分情况下,方法的调用需要有一个对象;函数不需要
  • 由于go中的所有传递都是值传递,也就是将数据复制一份再调用,所以如果想要修改原本对象的值,就要传递指针,进行引用传递
func 函数名 (参数) 返回值类型 {函数体} //函数定义
func (接收器) 方法名  (参数) 返回值类型 {函数体} // 方法定义
func main() {a := User{}a.setName() // 方法调用fmt.Println(a)setName(&a) // 函数调用fmt.Println(a)
}
/*{world 0}{hello 0}*/type User struct {Name stringage  int
}
//函数
func setName(u *User) {u.Name = "hello"
}
//方法
func (u *User) setName() {u.Name = "world"
}

值传递时可以通过返回值的方式修改目标对象

func main() {a := User{}a = a.setName() //需要显式给原变量赋值fmt.Println(a)a = setName(a)  //需要显式给原变量赋值fmt.Println(a)
}type User struct {Name stringage  int
}func setName(u User) User {u.Name = "hello"return u
}
func (u User) setName() User {u.Name = "world"return u
}

4.4.2 闭包

说到函数和方法,就必须说一下闭包

什么是闭包?

简单来说,就是函数内部引用函数外部变量,导致变量生命周期发生变化。这样的函数就叫做闭包

常见于函数返回值为另一个函数时

package mainimport "fmt"func main() {b := test()fmt.Println(b())fmt.Println(b())
}func test() func() int {a := 1return func() int {a++return a}
}

上面的函数导致变量a无法正常释放,导致变量逃逸

go build -gcflags="-m" main.go
# command-line-arguments
./main.go:11:6: can inline test
./main.go:13:9: can inline test.func1
./main.go:6:11: inlining call to test
./main.go:13:9: can inline main.test.func1
./main.go:7:15: inlining call to main.test.func1
./main.go:7:13: inlining call to fmt.Println
./main.go:8:15: inlining call to main.test.func1
./main.go:8:13: inlining call to fmt.Println
./main.go:6:11: func literal does not escape
./main.go:7:13: ... argument does not escape
./main.go:7:15: ~R0 escapes to heap
./main.go:8:13: ... argument does not escape
./main.go:8:15: ~R0 escapes to heap
./main.go:12:2: moved to heap: a
./main.go:13:9: func literal escapes to heap

4.5 Tag 字段标签

4.5.1定义

在reflect包中提供了获取字段名称、类型、Tag的方法(上文展示过获取名称和类型)

结构体StructField表示结构体的一个字段(reflect/type.go)

// A StructField describes a single field in a struct.
type StructField struct {// Name is the field name.Name string// PkgPath is the package path that qualifies a lower case (unexported)// field name. It is empty for upper case (exported) field names.// See https://golang.org/ref/spec#Uniqueness_of_identifiersPkgPath stringType      Type      // field typeTag       StructTag // field tag stringOffset    uintptr   // offset within struct, in bytesIndex     []int     // index sequence for Type.FieldByIndexAnonymous bool      // is an embedded field
}type StructTag string 

4.5.2 Tag规范

StructTag本质上就是字符串,理论上任何形式都符合规范。但通常情况下约定,Tag的格式应该是key:“value”

  • key:非空字符串,不能包含控制字符,空格,引号,冒号
  • value:双引号包围的字符串
  • 冒号前后不能有空格,多个value用逗号隔开,key之间用空格隔开
  • key一般表示用途,value表示控制指令;

4.5.3 Tag意义

  • Go语言反射机制可以给结构体成员赋值,用Tag可以决定赋值的动作
  • 可以使用定义好的Tag规则,参考规则就可以继续不同的操作
//仅对Tag值为true的字段赋值(Tag决定赋值动作)
type Person struct {Name string `assign:"true"`Age  int    `assign:"false"`
}func assignValues(v interface{}) {val := reflect.ValueOf(v).Elem() // 获取指针指向的值typ := val.Type()for i := 0; i < val.NumField(); i++ {field := val.Field(i)tag := typ.Field(i).Tag.Get("assign") // 获取字段的tagif tag == "true" {// 根据字段类型赋值switch field.Kind() {case reflect.String:field.SetString("Default Name")case reflect.Int:field.SetInt(25)}}}
}func main() {p := &Person{}assignValues(p)fmt.Printf("Person: %+v\n", p)
}
/*
Person: &{Name:Default Name Age:0}*/

下方例子使用了json:“kind,omitempty”,这个tag规定了字段为空不进行序列化;

import ("encoding/json""fmt"
)type Person struct {Name  string `json:"kind,omitempty"` //为空时不进行序列化Value intage   int
}func main() {// 创建一个 Person 实例p := Person{Name: "", Value: 100, age: 100}// 序列化为 JSONjsonData, _ := json.Marshal(p)fmt.Println(string(jsonData)) /*{"Value":100}*/
}

相关文章:

简单易懂,解析Go语言中的struct结构体

目录 4. struct 结构体4.1 初始化4.2 内嵌字段4.3 可见性4.4 方法与函数4.4.1 区别4.4.2 闭包 4.5 Tag 字段标签4.5.1定义4.5.2 Tag规范4.5.3 Tag意义 4. struct 结构体 go的结构体类似于其他语言中的class&#xff0c;主要区别就是go的结构体没有继承这一概念&#xff0c;但可…...

java给钉钉邮箱发送邮件

1.开通POP和IMAP 2.引入pom <dependency><groupId>javax.mail</groupId><artifactId>mail</artifactId><version>1.4.7</version> </dependency>3.逻辑 String host "smtp.qiye.aliyun.com"; String port "…...

C++和OpenGL实现3D游戏编程【连载23】——几何着色器和法线可视化

欢迎来到zhooyu的C++和OpenGL游戏专栏,专栏连载的所有精彩内容目录详见下边链接: 🔥C++和OpenGL实现3D游戏编程【总览】 1、本节实现的内容 上一节课,我们在Blend软件中导出经纬球模型时,遇到了经纬球法线导致我们在游戏中模型光照显示问题,我们在Blender软件中可以通过…...

大连本地知识库的搭建--数据收集与预处理_01

1.马蜂窝爬虫 编程语言&#xff1a;Python爬虫框架&#xff1a;Selenium&#xff08;用于浏览器自动化&#xff09;解析库&#xff1a;BeautifulSoup&#xff08;用于解析HTML&#xff09; 2.爬虫策略 目标网站&#xff1a;马蜂窝&#xff08;https://www.mafengwo.cn/&…...

github 推送的常见问题以及解决

文章目录 git add 的时候问题1为什么会发生这种情况&#xff1f;Git 的警告含义如何解决&#xff1f;1. **保持 Git 的默认行为&#xff08;推荐&#xff09;**2. **禁用自动转换**3. **仅在工作目录中禁用转换**4. **统一使用 LF&#xff08;跨平台开发推荐&#xff09;** git…...

stm32单片机个人学习笔记16(SPI通信协议)

前言 本篇文章属于stm32单片机&#xff08;以下简称单片机&#xff09;的学习笔记&#xff0c;来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记&#xff0c;只能做参考&#xff0c;细节方面建议观看视频&#xff0c;肯定受益匪浅。 STM32入门教程-2023版 细…...

Linux | RHEL / CentOS 中 YUM history / downgrade 命令回滚操作

注&#xff1a;英文引文&#xff0c;机翻未校。 在 RHEL/CentOS 系统上使用 YUM history 命令回滚升级操作 作者&#xff1a; 2daygeek 译者&#xff1a; LCTT DarkSun 为服务器打补丁是 Linux 系统管理员的一项重要任务&#xff0c;为的是让系统更加稳定&#xff0c;性能更加…...

BGP状态和机制

BGP邻居优化 为了增加稳定性,通常建议实验回环口来建立邻居。更新源:建立邻居和邻居所学习到的路由的下一跳。多跳:EBGP邻居建立默认选哟直连,因为TTL=1,如果非直连,必须修改TTL。命令备注peer 2.2.2.2 connect-interface lo1配置更新源peer 2.2.2.2 ebgp-max-hop 2配置T…...

温湿度监控设备融入智慧物联网

当医院的温湿度监控设备融入智慧物联网&#xff0c;将会带来许多新的体验&#xff0c;可以帮助医院温湿度监控设备智能化管理&#xff0c;实现设备之间的互联互通&#xff0c;方便医院对温湿度数据进行统一管理和分析。 添加智慧物联网技术&#xff0c;实现对医院温湿度的实时…...

smolagents学习笔记系列(五)Tools-in-depth-guide

这篇文章锁定官网教程中的 Tools-in-depth-guide 章节&#xff0c;主要介绍了如何详细构造自己的Tools&#xff0c;在之前的博文 smolagents学习笔记系列&#xff08;二&#xff09;Agents - Guided tour 中我初步介绍了下如何将一个函数或一个类声明成 smolagents 的工具&…...

前端面试真题 2025最新版

文章目录 写在前文CSS怪异盒模型JS闭包闭包的形成闭包注意点 CSS选择器及优先级优先级 说说flex布局及相关属性Flex 容器相关属性&#xff1a;Flex 项目相关属性 响应式布局如何实现是否用过tailwindcss&#xff0c;有哪些好处好处缺点 说说对象的 prototype属性及原型说说 pro…...

面试八股文--数据库基础知识总结(1)

1、数据库的定义 数据库&#xff08;DataBase&#xff0c;DB&#xff09;简单来说就是数据的集合数据库管理系统&#xff08;Database Management System&#xff0c;DBMS&#xff09;是一种操纵和管理数据库的大型软件&#xff0c;通常用于建立、使用和维护数据库。数据库系统…...

10. docker nginx官方镜像使用方法

本文介绍docker nginx官方镜像使用方法&#xff0c;因为第一次用&#xff0c;在加上对docker也不是很熟&#xff0c;中间踩了一些坑&#xff0c;为了避免下一次用又踩坑&#xff0c;因此记录如下&#xff0c;也希望能够帮到其它小伙伴。 官方镜像页面&#xff1a;https://hub.d…...

[Web 安全] PHP 反序列化漏洞 —— PHP 反序列化漏洞演示案例

关注这个专栏的其他相关笔记&#xff1a;[Web 安全] 反序列化漏洞 - 学习笔记-CSDN博客 PHP 反序列化漏洞产生原因 PHP 反序列化漏洞产生的原因就是因为在反序列化过程中&#xff0c;unserialize() 接收的值可控。 0x01&#xff1a;环境搭建 这里笔者是使用 PhpStudy 搭建的环…...

es-head(es库-谷歌浏览器插件)

1.下载es-head插件压缩包&#xff0c;并解压缩 2.谷歌浏览器添加插件 3.使用...

第二十:【路由的props配置】

作用&#xff1a;让路由组件更方便的收到参数&#xff08;可以将路由参数作为props传给组件&#xff09; {name:xiang,path:detail/:id/:title/:content,component:Detail, ​ 第一种方法&#xff1a;// props的对象写法&#xff0c;作用&#xff1a;把对象中的每一组key-valu…...

Vue 2全屏滚动动画实战:结合fullpage-vue与animate.css打造炫酷H5页面

引言 在移动端H5开发中&#xff0c;全屏滚动效果因其沉浸式体验而广受欢迎。如何快速实现带有动态加载动画的全屏滚动页面&#xff1f;本文将手把手教你使用 Vue 2、全屏滚动插件 fullpage-vue 和动画库 animate.css 3.5.1&#xff0c;打造一个高效且视觉冲击力强的H5页面。通…...

AF3 DataPipeline类process_pdb 方法解读

DataPipeline 类中的 process_pdb 方法用于从 PDB 文件中生成特定蛋白质链的特征,作为 AlphaFold3 预测的输入。它的流程与 process_mmcif 类似,但输入来源是 PDB 文件而非 MmcifObject。 源代码: def process_pdb(self,pdb_path: str,alignment_dir: str,is_distillation:…...

抓包工具 wireshark

1.什么是抓包工具 抓包工具是什么&#xff1f;-CSDN博客 2.wireshark的安装 【抓包工具】win 10 / win 11&#xff1a;WireShark 下载、安装、使用_windows抓包工具-CSDN博客 3.wireshark的基础操作 Wireshark零基础使用教程&#xff08;超详细&#xff09; - 元宇宙-Meta…...

OpenBMC:BmcWeb app获取socket

OpenBMC:BmcWeb app.run-CSDN博客 app对象在run函数中调用了setupSocket() static std::vector<Acceptor> setupSocket() {std::vector<Acceptor> acceptors;char** names = nullptr;int listenFdCount = sd_listen_fds_with_names(0, &names);BMCWEB_LOG_DE…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局&#xff1a;PCB行业的时代之问 在数字经济蓬勃发展的浪潮中&#xff0c;PCB&#xff08;印制电路板&#xff09;作为 “电子产品之母”&#xff0c;其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透&#xff0c;PCB行业面临着前所未有的挑战与机遇。产品迭代…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

C#中的CLR属性、依赖属性与附加属性

CLR属性的主要特征 封装性&#xff1a; 隐藏字段的实现细节 提供对字段的受控访问 访问控制&#xff1a; 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性&#xff1a; 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑&#xff1a; 可以…...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的&#xff0c;可以通过集中管理和高效资源的分配&#xff0c;来支持多个独立的网站同时运行&#xff0c;让每一个网站都可以分配到独立的IP地址&#xff0c;避免出现IP关联的风险&#xff0c;用户还可以通过控制面板进行管理功…...

Golang——9、反射和文件操作

反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一&#xff1a;使用Read()读取文件2.3、方式二&#xff1a;bufio读取文件2.4、方式三&#xff1a;os.ReadFile读取2.5、写…...

tomcat入门

1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效&#xff0c;稳定&#xff0c;易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...

TJCTF 2025

还以为是天津的。这个比较容易&#xff0c;虽然绕了点弯&#xff0c;可还是把CP AK了&#xff0c;不过我会的别人也会&#xff0c;还是没啥名次。记录一下吧。 Crypto bacon-bits with open(flag.txt) as f: flag f.read().strip() with open(text.txt) as t: text t.read…...

数据库正常,但后端收不到数据原因及解决

从代码和日志来看&#xff0c;后端SQL查询确实返回了数据&#xff0c;但最终user对象却为null。这表明查询结果没有正确映射到User对象上。 在前后端分离&#xff0c;并且ai辅助开发的时候&#xff0c;很容易出现前后端变量名不一致情况&#xff0c;还不报错&#xff0c;只是单…...