一文带你了解Go语言中的指针和结构体
作者:陈明勇 发布时间:2024-04-25 15:26:20
前言
前面的两篇文章对 Go 语言的基础语法和基本数据类型以及几个复合数据类型进行介绍,本文将对 Go 里面的指针和结构体进行介绍,也为后续文章做铺垫。
指针
在 Go
语言中,指针可以简单理解是一个地址,指针类型是依托于某一个类型而存在的,例如 Go
里面的基本数据类型 int
、float64
、string
等,它们所对应的指针类型为 *int
、*float64
、*string
等。
指针的定义
语法格式:var 指针变量名 *数据类型 = &变量
。
&
为取地址符号,通过 &
符号获取某个变量的地址,然后赋值给指针变量。
import (
"fmt"
)
func main() {
var num int = 666
var numPtr *int = &num
fmt.Println(numPtr) // num 变量的地址值 0xc00001c098
fmt.Println(&numPtr) // 指针变量本身的地址值 0xc00000a028
}
npmPtr
指针变量指向变量 num
,0xc00001c098
为 num
变量的地址,0xc00000a028
为指针变量本身的地址值。
使用 new(T)
函数创建指针变量
import (
"fmt"
)
func main() {
numPtr := new(int)
fmt.Println(numPtr) // 0xc000122058
fmt.Println(*numPtr) // 0
}
new(T)
函数为每个类型分配一片内存,内存单元保存的是对应类型的零值,函数返回一个指针类型。
错误的类型地址赋值
func main() {
var num float64 = 666
var numPtr *int = &num // cannot use &num (value of type *float64) as type *int in variable declaration
}
当指针所依托的类型与变量的类型不一致时,Go 编译器会报错,类型不匹配。
获取和修改指针所指向变量的值
通过指针获取所指向变量的值
func main() {
var num int = 666
var numPtr *int = &num
// 获取 num 的值
fmt.Println(*numPtr) // 666
}
对指针使用 *
操作符可以获取所指向变量的值。
通过指针修改所指向变量的值
import (
"fmt"
)
func main() {
var num int = 666
var numPtr *int = &num
// 修改 num 的值
*numPtr = 555
fmt.Println(num) // 555
}
同时也可以对指针使用 *
操作符修改所指向变量的值。
结构体
通过上一篇文章,我们了解了数组和切片的特点,它们可以存储一组相同类型的数据,而结构体,它可以由 0 个或多个字段组成,每个字段的数据类型可以一样,也可以不一样。结构体可以表示一个对象,例如:人,人包含的一些字段有姓名、性别和年龄等。
结构体定义
语法格式:
type XXX struct {
/*
结构体字段定义区域
*/
}
XXX
为结构体的名字,下面以人为对象,引入结构体
// Person定义一个人的结构体
type Person struct {
// 姓名
Name string
// 年龄
Age int
// 性别
Sex string
// 身份证号
idNumber string
}
上述代码定义了人的结构体 Person
,包含四个字段,字段的命名规则和变量是一样的,前三个字段首字母大写,可以被包外访问,第四个字段首字母小写,表示只能在包内访问。 除了上述的定义方式以外,结构体里还可以内嵌结构体
// Person 定义一个人的结构体
type Person struct {
// 姓名
Name string
// 年龄
Age int
// 性别
Sex string
// 身份证号
idNumber string
}
// Phone 手机结构体
type Phone struct {
// 品牌
Brand string
// 拥有者
Owner Person
}
上述代码定义了 Person
结构体和 Phone
结构体,Phone
结构体拥有两个字段,分别为 Brand
品牌和 Owner
拥有者,Owner
属性的类型,指定为我们所自定义的 Person
结构体。以这种方式定义的结构体字段,我们可以称为嵌入字段(Embedded Field)。也可以将这种字段称为匿名字段。
结构体的创建方式
1、声明一个结构体变量
// Person 定义一个人的结构体
type Person struct {
// 姓名
Name string
// 年龄
Age int
// 性别
Sex string
// 身份证号
idNumber string
}
func main() {
var person Person
fmt.Println(person.Name) // ""
fmt.Println(person.Age) // 0
fmt.Println(person.Sex) // ""
fmt.Println(person.idNumber) // ""
// 修改结构体字段的值
person.Name = "chenmingyong"
fmt.Println(person.Name) // "chenmingyong"
}
通过声明一个结构体变量,隐式创建一个结构体变量,这个结构体变量各个字段值默认为零值,也就是对应类型的默认值。
结构体属性的值,可以通过 变量.字段名
的方式获取,同时也可以通过此方式对字段值进行修改。
2、使用复合字面值进行显式初始化结构体对象
import "fmt"
// Person 定义一个人的结构体
type Person struct {
// 姓名
Name string
// 年龄
Age int
// 性别
Sex string
// 身份证号
idNumber string
}
func main() {
person := Person{
"chenmingyong",
18,
"男",
"xxxxxxxxx",
}
fmt.Println(person) // {chenmingyong 18 男 xxxxxxxxx}
}
上述代码根据字段的顺序进行赋值,实际上,Go 语言并不推荐我们用这种方式进行赋值,因为可能会带来一些问题,例如结构体的某个中间的字段被删除或者字段的顺序改变了,那么我们需要维护对应代码,调整赋值的顺序。
上述创建结构体的方式有弊端,因此我们需要换一种方法,如下第三种方法。
3、 使用 field:value
形式的复合字面值进行显式初始化结构体对象
import "fmt"
// Person 定义一个人的结构体
type Person struct {
// 姓名
Name string
// 年龄
Age int
// 性别
Sex string
// 身份证号
idNumber string
}
func main() {
person := Person{
Sex: "男",
Age: 18,
Name: "chenmingyong",
idNumber: "xxxxxxxxx",
}
fmt.Println(person) // {chenmingyong 18 男 xxxxxxxxx}
}
通过以上的方式,我们就不被字段的顺序所约束了。
4、通过 new(T)
函数创建结构体指针
// Person 定义一个人的结构体
type Person struct {
// 姓名
Name string
// 年龄
Age int
// 性别
Sex string
// 身份证号
idNumber string
}
func main() {
person := new(Person)
(*person).Name = "chenmignyong"
fmt.Println((*person).Name) // chenmignyong
// 简化赋值,底层自动转换成 (*person).Age = 18
person.Age = 18
fmt.Println(person.Age) // 18
}
前面提到过,访问指针所指向变量的值,需要使用 *
操作符,但在结构体这里有点特殊,如果不加 *
的话,底层会将 person.Age = 18
转成 (*person).Age = 18
。
小结
本文对指针和结构体进行了介绍,也指出使用指针和结构体时需要注意的一些地方。因为本文是基于了解的层面去写的文章,一些深入的知识并没有提到,然后也没有提到结构体的方法,是因为打算留到后面和函数一起去介绍。
来源:https://juejin.cn/post/7169961029328175112


猜你喜欢
- sql的max之类的聚合函数只能针对同一列的n行运算,如果对n列运算,一般都用case 语句来判断,如果列少还比较容易写,列多了就麻烦了。-
- 使用WebDriver在Chrome浏览器上进行测试时,需要从http://chromedriver.storage.googleapis.
- logconfig.json{ "version":1, "disable_existing_loggers&
- 今天的这一章节我们来学习一下,Python 中的三个高级函数,也被称之为 魔法函数。之所以把他们交的这么高级,主要是因为它们返回的
- panic源码解读前言本文是在go version go1.13.15 darwin/amd64上进行的panic的作用panic能够改变程
- 什么是 Socket?Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网
- 其实这个东西没什么技术含量,就是给大家提供一个给表格加滚动条的思路。运行代码框<html><head><tit
- 什么是词干提取?在语言形态学和信息检索里,词干提取是去除词缀得到词根的过程─—得到单词最一般的写法。对于一个词的形态词根,词干并不需要完全相
- 方法1:/** 功能:数据备份/恢复文件简易方法* 以日期为单位,一天一个备份文件,以当天最后备份为准* 用提交表单的形式进行操作,* 其中
- 目录概述索引数据结构二叉树红黑树B-TreeB+TreeHash索引InnoDB 索引实现(聚集)索引文件和数据文件是分离的(非聚集)聚集索
- CAST函数用于将值从一种数据类型转换为表达式中指定的另一种数据类型语法CAST(value AS datatype)AS关键字用于分隔两个
- 前言通过后端接口的返回值,动态添加路由,是作为权限控制的一种常见方式,本文将简单讲解如何在Vue3中动态添加路由。示例数据[ {
- 一.docx模块Python可以利用python-docx模块处理word文档,处理方式是面向对象的。也就是说python-docx模块会把
- 官方示例:uni-popup 弹出层 - DCloud 插件市场弹出层组件用于弹出一个覆盖到页面上的内容,使用场景如:底部弹出分
- 你是否曾为表单设计感到过沮丧或不知所措呢?接下来三篇文章,希望能彻底改变你的看法,真正爱上Web表单设计。首先感谢Luke Wroblews
- 本文实例为大家分享了js实现简单放大镜效果的具体代码,供大家参考,具体内容如下效果效果,鼠标在原图片移动,黄色小盒子跟随鼠标移动,黄色小盒子
- 爬取了下小猪短租的网站出租房信息但是输出的时候是这种:百度了下。python2.7在window上的编码确实是个坑解决如下如果是个字典的话要
- 读取一个已经保存了的字典f = open('dict_th','r')a = f.read()dict_hi
- 首先,运行 Python 解释器,导入 re 模块并编译一个 RE:#!python Python 2.2.2 (#1, Feb 10 20
- GetRows 方法 将 Recordset 对象的多个记录复制到数组中。 语法 代码如下: array = recordset.GetR