golang结构体与指针类型

embedded/2025/4/1 4:03:13/

结构体与指针类型

指针类型字段

具名字段

举例

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.ppmy.cn/embedded/176721.html

相关文章

ECharts实现数据可视化

ECharts实现数据可视化 一、Echarts的简介二、Echarts使用教程1.下载echarts.min.js文件2.编写echarts代码(1)创建渲染实列(2)修改option达到预期的效果(3)创建配置项到实例中 三、Echarts的基础配置四、前…

MySQL使用rpm安装——Linux版

MySQL 1、卸载Mariadb/MySQL2、下载MySQL3、安装MySQL4、配置MySQL5、启动MySQL6、设置MySQL 1、卸载Mariadb/MySQL # 1、卸载 yum list installed | grep mariadb | xargs yum remove -y yum list installed | grep mysql | xargs yum remove -y # 2、删除文件夹 find / -nam…

PostgreSQL 数据库源码编译安装全流程详解 Linux 8

PostgreSQL 数据库源码编译安装全流程详解 Linux 8 1. 基础环境配置1.1 修改主机名1.2 配置操作系统yum源1.3 安装操作系统依赖包1.4 禁用SELINUX配置1.5 关闭操作系统防火墙1.6 创建用户和组1.7 建立安装目录1.8 编辑环境变量 2. 源码方式安装(PG 16)2.…

游戏MOD伴随盗号风险,仿冒网站借“风灵月影”窃密【火绒企业版V2.0】

游戏MOD(即游戏修改器)是一种能够对游戏进行修改或增强的程序,因其能够提升游戏体验,在玩家群体中拥有一定的市场。然而,这类程序大多由第三方开发者制作,容易缺乏完善的安全保障机制,这就为不法…

如何在Linux CentOS上安装和配置Redis

如何在Linux CentOS上安装和配置Redis 大家好,我是曾续缘。欢迎来到本教程!今天我将向您介绍在Linux CentOS上安装和配置Redis的详细步骤。Redis是一个高性能的键值存储系统,常用于缓存、消息队列和数据持久化等应用场景。让我们一起开始吧&…

NVIDIA TensorRT-LLM:高性能大语言模型推理框架详解

NVIDIA TensorRT-LLM:高性能大语言模型推理框架详解 引言 随着大语言模型(LLMs)在各行各业的应用日益广泛,如何高效地部署这些模型以实现低延迟、高吞吐量的推理服务成为了一个关键挑战。NVIDIA TensorRT-LLM 是 NVIDIA 专为大语…

UDP通信实现

一、Socket简介(套接字) TCP/IP 五层网络模型的应用层编程接口称为Socket API, Socket( 套接字 ) ,它是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。 一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换…

MongoDB 面试备战指南

MongoDB 面试备战指南 一、基础概念 1. MongoDB是什么类型的数据库?和关系型数据库有什么区别? 答案: MongoDB是文档型NoSQL数据库,核心区别: 数据模型:存储JSON-like文档(动态schema&#xf…