golang结构体与指针类型

结构体与指针类型

指针类型字段

具名字段

举例

package struct_knowledgeimport "fmt"//结构体字段为指针类型
func StructWithPoint(){type Student struct{name *string}var lisa Studentfmt.Printf("赋值前,Student的实例的值%#v\n",lisa)//错误的赋值方法//报错:panic: runtime error: invalid memory address or nil pointer dereference// *lisa.name = "hello"//正确的赋值方法1name := "lisa"lisa.name = &namefmt.Printf("赋值后,Student的实例的值%#v\n",lisa)//正确赋值方法2//先分配内存再赋值lisa.name = new(string)*lisa.name = "hello"fmt.Printf("赋值后,Student的实例的值%#v\n",lisa)
}

结果

赋值前,Student的实例的值struct_knowledge.Student{name:(*string)(nil)}
赋值后,Student的实例的值struct_knowledge.Student{name:(*string)(0xc000186050)}
赋值后,Student的实例的值struct_knowledge.Student{name:(*string)(0xc000186060)}

注意事项

一定要注意指针的内存分配,没有分配内存的指针不能赋值。

//方法1:这种是在栈上分配内存
name := "lisa"
lisa.name = &name
fmt.Printf("赋值后,Student的实例的值%#v\n",lisa)//方法2:在堆上赋值
//先分配内存再赋值
lisa.name = new(string)
*lisa.name = "hello"
fmt.Printf("赋值后,Student的实例的值%#v\n",lisa)

匿名字段

匿名指针类型字段,实际上字段名就是去除*号的类型名,举例

//报错:string redeclared
type Student struct{*stringstring
}//实际上等价于
type Student struct{//出现了同名字段所以报错string *stringstring string
}

举例

package struct_knowledgeimport "fmt"//结构体字段为指针类型
func StructWithPoint(){type Student struct{*string}var lisa Studentfmt.Printf("赋值前,Student的实例的值%#v\n",lisa)//错误的赋值方法//报错:panic: runtime error: invalid memory address or nil pointer dereference// *lisa.string = "hello"//正确的赋值方法1name := "lisa"lisa.string = &namefmt.Printf("赋值后,Student的实例的值%#v\n",lisa)//正确赋值方法2//先分配内存再赋值lisa.string = new(string)*lisa.string = "hello"fmt.Printf("赋值后,Student的实例的值%#v\n",lisa)
}

结果

赋值前,Student的实例的值struct_knowledge.Student{name:(*string)(nil)}
赋值后,Student的实例的值struct_knowledge.Student{name:(*string)(0xc0000140a0)}
赋值后,Student的实例的值struct_knowledge.Student{name:(*string)(0xc0000140b0)}

指针类型嵌套结构体

具名结构体

和普通字段的处理情况一样,举例

举例

package struct_knowledge
import "fmt"
//结构体指针
func StructWithPoint1(){type Animal struct{name string }type Dog struct{Anl *Animal}var dog Dog/*报错:panic: runtime error: invalid memory address or nil pointer dereference[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x490830]*/// dog.Anl.name = "duby"// fmt.Printf("赋值后,dog的实例的值%#v\n",dog)//方法1:先分配内存dog.Anl = &Animal{}dog.Anl.name = "duby"fmt.Printf("赋值后,dog的实例的值%#v\n",dog)//方法2:使用new方法dog.Anl = new(Animal)dog.Anl.name = "duby"fmt.Printf("赋值后,dog的实例的值%#v\n",dog)
}

结果

赋值后,dog的实例的值struct_knowledge.Dog{Anl:(*struct_knowledge.Animal)(0xc0000140a0)}
赋值后,dog的实例的值struct_knowledge.Dog{Anl:(*struct_knowledge.Animal)(0xc0000140b0)}

匿名结构体

和匿名字段一样

type Animal struct{name string 
}
type Dog struct{*Animal
}//等价于
type Dog struct{Animal *Animal
}

注意

当使用指针类型的匿名结构体后,普通匿名结构体的特性就失去了,

举例

//匿名结构体
func StructWithPoint2(){type Animal struct{name string }type Dog struct{*Animal}var dog Dog/*报错:panic: runtime error: invalid memory address or nil pointer dereference[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x490830]*/// dog.name = "Mao"// fmt.Printf("赋值后,dog的实例的值%#v\n",dog)//指针都需要先分配nick := &Animal{name:"Mao"}dog = Dog{nick,}fmt.Printf("赋值后,dog的实例的值%#v\n",dog)//也可以采用具名结构体一样的处理方式,例如dog.Animal = new(Animal)dog.Animal.name = "duby"fmt.Printf("赋值后,dog的实例的值%#v\n",dog)}

对于普通匿名结构体,我们可以用顶层结构体名.字段名来访问嵌套结构体。

但是指针类型的嵌套结构体会报指针未分配内存的问题,所以我们我们必须给指针类型的结构体分配内存。

结果

赋值后,dog的实例的值struct_knowledge.Dog{Animal:(*struct_knowledge.Animal)(0xc0000140a0)}
赋值后,dog的实例的值struct_knowledge.Dog{Animal:(*struct_knowledge.Animal)(0xc0000140b0)}

接收者类型

结构体的方法的接收者可以为指针也可以为值。

由于结构体是值类型的,所以当方法接收者使用的是值时,方法内的操作与外部无关;

当方法接收者是指针时,方法内的操作会影响到外部的原始变量。

举例

package struct_knowledgeimport "fmt"type Day struct{Name string Order int 
}func (d Day) ChangeVal(){if d.Order==1 {d.Name = "星期一"}else{d.Name = "未知"}fmt.Printf("接收者为值类型时,方法内的实例值为%#v\n",d)
}func (d *Day) ChangeValByPorint(){if d.Order==1 {d.Name = "星期一"}else{d.Name = "未知"}fmt.Printf("接收者为值类型时,方法内的实例值为%#v\n",d)
}

调用

package mainimport ("fmt""go_learn/struct_knowledge"
)
func main(){var day struct_knowledge.Dayday.Order = 1day.ChangeVal()fmt.Printf("接收者为值类型时,方法外的实例值为%#v\n",day)day.ChangeValByPorint()fmt.Printf("接收者为指针类型时,方法外的实例值为%#v\n",day)
}

结果

接收者为值类型时,方法内的实例值为struct_knowledge.Day{Name:"星期一", Order:1}
接收者为值类型时,方法外的实例值为struct_knowledge.Day{Name:"", Order:1}
接收者为值类型时,方法内的实例值为&struct_knowledge.Day{Name:"星期一", Order:1}
接收者为指针类型时,方法外的实例值为struct_knowledge.Day{Name:"星期一", Order:1}

理解

1.方法的接收者是指针还是值不是由其调用者决定的,而是由方法本身决定的,如果方法的接收者为指针,方法就会自动取调用者的指针。

var day struct_knowledge.Day
day.Order = 1//调用者都是 Day实例
// changeVal这个方法使用的是实例的值
day.ChangeVal()
//ChangeValByPorint这个方法使用的是实例的指针
day.ChangeValByPorint()

2.结构体指针问题:结构体实例指针的使用形式和其值的使用形式是一样的,所以一定要明确使用的是值还是指针。

golang为了美观,将数组和结构体实例指针前的*去除了。

func (d Day) ChangeVal(){if d.Order==1 {d.Name = "星期一"}else{d.Name = "未知"}fmt.Printf("接收者为值类型时,方法内的实例值为%#v\n",d)
}func (d *Day) ChangeValByPorint(){if d.Order==1 {d.Name = "星期一"}else{d.Name = "未知"}fmt.Printf("接收者为值类型时,方法内的实例值为%#v\n",d)
}

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

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

相关文章

NetMizer-日志管理系统-远程命令执行漏洞挖掘

漏洞描述:NetMizer 日志管理系统 cmd.php中存在远程命令执行漏洞,攻击者通过传入 cmd参数即可命令执行 1.fofa搜素语句 title"NetMizer 日志管理系统" 2.漏洞验证 网站页面 验证POC /data/manage/cmd.php?cmdid

Contactile三轴触觉传感器:多维力感赋能机器人抓取

在非结构化环境中,机器人对物体的精准抓取与操作始终面临巨大挑战。传统传感器因无法全面感知触觉参数(如三维力、位移、摩擦),难以适应复杂多变的场景。Contactile推出的三轴触觉力传感器,通过仿生设计与创新光学技术…

OpenCV三维解算常用方法C++

如果标定过程是通过OpenCV张正友标定法实现的,得到的内参外参保存在.txt文件中是这样的形式: ① 内参intrinsics.txt: ② 外参extrinsics.txt: 那么可以通过如下方法读取.txt文件获取左右相机内外参,主要包括三维解算…

栈和队列相关知识题目

栈的底层原理 栈(Stack)是一种后进先出(LIFO)​的线性数据结构,所有操作(如插入、删除)仅在栈顶进行。它的底层实现可以是数组或链表,具体取决于编程语言和应用场景。 1.基于数组实…

【实战案例】永洪vividime:精准赋能零售行业,实现数据洞察与业务增长

在零售食品行业变革加速、市场竞争白热化的背景下,XX集团作为休闲食品领域头部企业,面临消费趋势变化、宏观经济承压及业绩增长乏力的多重挑战。为破解增长困境,集团将“收入增长金额”确立为核心战略指标(北极星指标)…

一些题目记录

别人面经题目记录 https://zhuanlan.zhihu.com/p/32626732052 实现 NMS,七八次,很高频; 实现 MultiHeadSelfAttention,大概 三四次; 用 Numpy 或者 List 实现MLP 的前向和反向,4次; Leetcode …

面试题分享-多线程顺序打印奇偶数

目录 1.题目详情 2.解题思路 2.1.分析题目 2.2.解析思路 3.代码实现 4.运行结果 1.题目详情 昨天刷抖音,遇到一个面试题,描述如下: 请使用两个线程,分别顺序交替打印奇数和偶数,直到10为止。例如有两个线程&#…

模型 杜根定律

系列文章分享模型,了解更多👉 模型_思维模型目录。信心>能力、行动导向、未来时态。 1 杜根定律的应用 1.1 公共政策博弈——底特律市长杜根的保险改革攻坚战 核心挑战:底特律市长Mike Duggan面临汽车保险费率畸高导致居民陷入贫困循环的…

关于在vscode中的Linux 0.11 应用程序项目的生成和运行

首先我们需要需要查看镜像文件 查看软盘镜像文件 floppyb.img 中的内容 在 VSCode 的“Terminal”菜单中选择“Run Build Task...”,会在 VSCode 的顶部中间位置弹出一个 可以执行的 Task 列表,选择其中的“打开 floppyb.img”后会使用 Floppy Editor …

使用CSS3实现炫酷的3D视差滚动效果

使用CSS3实现炫酷的3D视差滚动效果 这里写目录标题 使用CSS3实现炫酷的3D视差滚动效果项目概述核心技术实现1. 3D空间的创建2. 视差层级设置3. 动画效果实现流星动画月亮发光效果 技术难点与解决方案1. 层级重叠问题2. 性能优化3. 响应式适配 开发心得总结 项目概述 在这个项目…

作业12 (2023-05-15 指针概念)

第1题/共11题【单选题】 关于指针的概念,错误的是:( ) A.指针变量是用来存放地址的变量 B.指针变量中存的有效地址可以唯一指向内存中的一块区域 C.野指针也可以正常使用 D.局部指针变量不初始化就是野指针 回答正确 答案解析: A:正确,指针变量中存储的是一个地址,指…

【ESP32S3】esp32获取串口数据并通过http上传到前端

通过前面的学习(前面没发过,因为其实就是跑它的demo)了解到串口配置以及开启线程实现功能的工作流程,与此同时还有esp32作为STA节点,将数据通过http发送到服务器。 将这两者联合 其实是可以得到一个:esp32获…

《鸿蒙携手AI:解锁智慧出行底层逻辑》

在科技飞速发展的当下,智慧出行成为人们对未来交通的美好期许,而鸿蒙系统与人工智能的深度融合,正为这一愿景的实现提供强大助力。从技术原理角度深入剖析,鸿蒙系统究竟如何支撑人工智能在智慧出行场景中的应用呢?这背…

MyBatis-Plus缓存机制深度解析与SpringBoot整合实战

一、MyBatis-Plus缓存机制全景解析 MyBatis-Plus在MyBatis原生缓存基础上进行了深度增强,形成了多层次的缓存体系: 1. 缓存层级架构 应用层 ├── MP扩展缓存(多租户/逻辑删除) ├── 二级缓存(Mapper级别,跨Session共享) └── 一级缓存(SqlSession级别,默认开…

Day38 | 1365. 有多少小于当前数字的数字、941. 有效的山脉数组、1207. 独一无二的出现次数、283. 移动零、189. 轮转数组

1365. 有多少小于当前数字的数字 题目链接&#xff1a;1365. 有多少小、于当前数字的数字 - 力扣&#xff08;LeetCode&#xff09; 题目难度&#xff1a;简单 代码&#xff1a; class Solution {public int[] smallerNumbersThanCurrent(int[] nums) {Map<Integer,Inte…

数据人的进阶之路:四年数仓实践与成长思考

前言 在数据仓库开发的过程中&#xff0c;常常会遇到很多值得思考的问题&#xff0c;它们不仅关乎技术的深度&#xff0c;也涉及业务理解、个人的成长&#xff0c;甚至是数据行业未来的价值。回顾过去的经历&#xff0c;有很多问题反复出现&#xff0c;甚至成为绕不开的课题&am…

大文件分片上传及断点续传实现

使用 支持分片上传及断点续传 前端使用 vue 2 后端使用 springboot 源码在私信

图解AUTOSAR_SWS_IOHardwareAbstraction

AUTOSAR IO硬件抽象层详解 基于AUTOSAR标准的IO硬件抽象层设计与实现指南 目录 1. 概述2. 架构设计 2.1 模块架构概览2.2 内部组件结构2.3 与其他模块的交互接口 3. 状态机 3.1 状态定义3.2 状态转换3.3 状态行为 4. ADC信号处理流程 4.1 初始化流程4.2 转换请求和处理4.3 通知…

Python正则表达式(一)

目录 一、正则表达式的基本概念 1、基本概念 2、正则表达式的特殊字符 二、范围符号和量词 1、范围符号 2、匹配汉字 3、量词 三、正则表达式函数 1、使用正则表达式&#xff1a; 2、re.match()函数 3、re.search()函数 4、findall()函数 5、re.finditer()函数 6…

北京交通大学第三届C语言积分赛

作者有言在先&#xff1a; 题解的作用是交流思路&#xff0c;不是抄作业的。可以把重点放在思路分析上而不是代码上&#xff0c;毕竟每个人的代码风格是不一样的&#xff0c;看别人的代码就跟做程序填空题一样。先看明白思路再看代码。 还有就是&#xff0c;deepseek真的很好用…