一文带你了解Go语言中的指针和结构体

 更新时间:2022年11月28日 11:22:40   作者:陈明勇  
前面的两篇文章对 Go 语言的基础语法和基本数据类型以及几个复合数据类型进行介绍,本文将对 Go 里面的指针和结构体进行介绍,也为后续文章做铺垫,感兴趣的可以了解一下

前言

前面的两篇文章对 Go 语言的基础语法和基本数据类型以及几个复合数据类型进行介绍,本文将对 Go 里面的指针和结构体进行介绍,也为后续文章做铺垫。

指针

Go 语言中,指针可以简单理解是一个地址,指针类型是依托于某一个类型而存在的,例如 Go 里面的基本数据类型 intfloat64string 等,它们所对应的指针类型为 *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 指针变量指向变量 num0xc00001c098num 变量的地址,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

小结

本文对指针和结构体进行了介绍,也指出使用指针和结构体时需要注意的一些地方。因为本文是基于了解的层面去写的文章,一些深入的知识并没有提到,然后也没有提到结构体的方法,是因为打算留到后面和函数一起去介绍。

到此这篇关于一文带你了解Go语言中的指针和结构体的文章就介绍到这了,更多相关Go语言指针 结构体内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • GO语言的map类型实例详解

    GO语言的map类型实例详解

    这篇文章主要介绍了GO语言的map类型实例详解,包括对map的创建,赋值,排序,删除,等操作需要的朋友可以参考下
    2022-12-12
  • Golang的第一个程序-Hello World

    Golang的第一个程序-Hello World

    这篇文章主要介绍了第一个Go程序-Hello World,在编写第一个go程序之前,我们要将系统的环境变量配好,下面来看具体的编一过程吧,需要的小伙伴可以参考一下
    2022-01-01
  • Golang操作excel的技巧与方法

    Golang操作excel的技巧与方法

    在Golang中操作Excel可以包括读取、写入和编辑Excel文件,你可以定义函数或方法来执行这些操作,本文给大家介绍了Golang操作excel的技巧与方法,文中有详细的代码讲解,需要的朋友可以参考下
    2024-05-05
  • golang如何使用gos7读取S7200Smart数据

    golang如何使用gos7读取S7200Smart数据

    文章介绍了如何使用Golang语言的Gos7工具库读取西门子S7200Smart系列PLC的数据,通过指定数据块号、起始字节偏移量和数据长度,可以精确读取所需的数据,感兴趣的朋友跟随小编一起看看吧
    2024-12-12
  • go time.After优化后性能提升34%内存减少67%

    go time.After优化后性能提升34%内存减少67%

    这篇文章主要介绍了go语言time.After优化后性能提升34%内存减少67%实例分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • 基于Go编写一个可视化Navicat本地密码解析器

    基于Go编写一个可视化Navicat本地密码解析器

    这篇文章主要给大家介绍了基于Go编写一个可视化Navicat本地密码解析器的方法,文中有详细的代码示例和图文介绍,有需要的朋友可以参考阅读本文
    2023-08-08
  • Golang 并发的实现

    Golang 并发的实现

    本文主要介绍了Golang 并发的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-05-05
  • Golang使用Swag搭建api文档的全过程

    Golang使用Swag搭建api文档的全过程

    Gin是Golang目前最为常用的Web框架之一,公司项目验收需要API接口设计说明书(Golang后端服务基于Gin框架编写),所以本文给大家介绍了Golang使用Swag搭建api文档的全过程,需要的朋友可以参考下
    2024-02-02
  • 读取Go项目中的配置文件的方法

    读取Go项目中的配置文件的方法

    本文主要介绍了读取Go项目中的配置文件的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • 使用Golang开发一个简易版shell

    使用Golang开发一个简易版shell

    这篇文章主要为大家详细介绍了如何使用Golang开发一个简易版shell,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-02-02

最新评论