首页 > 其他分享 >一文了解 Go 中的指针和结构体

一文了解 Go 中的指针和结构体

时间:2022-11-25 23:41:14浏览次数:33  
标签:一文 person int fmt Person Go 指针 string

耐心和持久胜过激烈和狂热。

前言

前面的两篇文章对 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​​ 为指针变量本身的地址值。

一文了解 Go 中的指针和结构体_Go

  • 使用 ​​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​​。

小结

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

如果本文对你有帮助,欢迎点赞收藏加关注,如果本文有错误的地方,欢迎指出!

标签:一文,person,int,fmt,Person,Go,指针,string
From: https://blog.51cto.com/u_15878295/5888006

相关文章

  • 基于Docker的Golang开发
    一、Docker用于开发Docker不仅用于部署,它还可以用于开发。1、为什么要在开发中使用Docker主要有以下几个原因。1)一致的开发环境使用Docker,可以保证整个研发团队使用一致的开......
  • 【重磅】Google 分布式 TensorFlow,像 Android 一样带来 AI 复兴?
     新智元原创1【新智元导读】今天,Google发布了分布式TensorFlow。Google的博文介绍了TensorFlow在图像分类的任务中,100个GPUs和不到65小时的训练时间下,达到了78......
  • Golang中一个不错的处理 JSON 的库 go-dproxy
    国庆七天,你是吃多了,还是睡多了?放假七天转眼即逝,接下来的七天可能你又觉得会很漫才。言归正传。Golang虽然自己就带了JSON(encoding/json)处理的库,也有第三方的simplejs......
  • Mac上安装mongoDB详细教程
    MacOSX平台安装MongoDBMongoDB提供了OSX平台上64位的安装包,你可以在官网下载安装包。下载地址:https://www.mongodb.com/download-center#community 从Mongo......
  • Daphne 部署 Django ASGI 的常见错误与解决方法
    问题1django.core.exceptions.AppRegistryNotReady:Appsaren'tloadedyet.处理方法:修改asgi.py,增加django.setup()注意:django.setup()要置顶,不能在底部,否则使用da......
  • 一文学会使用Vue3
    一文学会使用Vue3本文适合Vue初学者,或者Vue2迁移者,当然还是建议Vue3官网完全过一遍。不适合精通原理,源码的大佬们。先推荐两个vscode插件Volar首先推荐Volar,使用vscode......
  • 8.8.8.8,Google推出免费DNS解析服务器
    Google今天又给了我们一个惊喜,并沉重的打击了OpenDNS:他们刚刚宣布向所有的互联网用户提供一组快速,安全并且完全免费的DNS解析服务器,地址分别是:8.8.8.88.8.4.4我想这组ip看......
  • Go Testing单元测试
    使用Golang编程时,一般只有在写最终的main函数时我们才有机会调用某个函数进行测试,在大型项目中如果只负责编写某个非main模块时应当如何测试函数的可用性?Golang提供了Test......
  • go源码学习(零):前置知识-编译过程
    编译原理-从源码到机器码任何一门高级语言,要想最终能够在机器上执行那么就一定要从源码生成机器码,因为对于机器来说,它只认同由0和1组成的二进制程序。从人类可读的源码到......
  • 14、go的反射
    基本数据类型反射//利用函数的参数定义为空接口functestRefect(iinterface{}){ //调用TypeOf函数,返回reflect.Type类型的数据 reType:=reflect.TypeOf(i) fmt......