Go 编程 | 连载 14 - 指针 Pointer

简介: Go 编程 | 连载 14 - 指针 Pointer

一、指针

指针的概念以及定义

一个变量交换的例子

交换两个变量的值在排序过程中是一个高频操作,交换变量值最直接的方式就是通过一个临时变量来实现交换,在 Go 中可以这么来实现:

func main() {
   a := 10
   b := 20
   switchVal(a, b)
   fmt.Println(a, b)
}
// 定义一个函数:交换两个变量的值
func switchVal(a int, b int) {
   temp := a
   a = b
   b = temp
}
复制代码

执行上述代码,输出结果如下:

10 20
复制代码

根据结果来看并没有成功的实现交换两个变量的值,为什么?因为整型是值类型,作为函数参数时会将拷贝非副本作为实际的参数。

image.png

那么如何修改呢?

func main() {
   a := 10
   b := 20
   switchVal(&a, &b)
   fmt.Println(a, b)
}
// 交换两个变量的值
func switchVal(a *int, b *int) {
   temp := *a
   *a = *b
   *b = temp
}
复制代码

执行上述代码,输出结果如下:

20 10
复制代码

根据输出结果可以确定,a 和 b 两个变量的变量值交换成功。

指针

上述代码中的 & 在之前的文章有提到过,表示获取变量的内存地址,那么 switchVal 函数中的 *int 又表示什么?

*int 表示指针类型,指针是一种数据类型,指针中存储的是内存地址,而这个内存地址指向一块具体的内存,这块具体的内存中保存着个中类型的数据。

指针类型包含两个部分,第一个是 * 符号,表示是指针类型,第二个组成部分是基本数据类型标识符,表示指针所执行的内存地址中存储的数据类型。

指针变量与普通变量不同的是,普通变量存储的直接就是变量值,而指针存储的是变量的内存地址。

image.png

func main() {
   var yankee int = 200
   // 定义指针
   var zulu *int = &yankee
   fmt.Printf("%T, %v, %v\n", yankee, yankee, &yankee)
   fmt.Printf("%T, %v, %v\n", zulu, zulu, *zulu)
}
复制代码

执行上述代码,输出结果如下:

int, 200, 0xc0000b2008
*int, 0xc0000b2008, 200
复制代码

在普通变量前添加 & 就可以获得该变量的内存地址,在指针变量前添加 * 就可以获取该指针变量中的内存地址所指向的值。如果要修改指针变量内存地址指向的值只需要 *指针变量=newVal 即可。

当然定义指针变量时也可以省略 var 关键字,直接使用 := 来定义。

func main() {
   xray := 1.0
   whiskey := "Go"
   victor := []string{"Stark", "Thor", "Steve"}
   uniform := [...]int{1, 3, 5, 7, 9}
   tango := map[string]string{
      "code":   "Tango 6",
      "number": "6",
   }
   tangoCode := tango["code"]
   fmt.Printf("%T, %v\n", &xray, &xray)
   fmt.Printf("%T, %v\n", &whiskey, &whiskey)
   fmt.Printf("%T, %v\n", &victor[0], &victor[0])
   fmt.Printf("%T, %v\n", &uniform[0], &uniform[0])
   fmt.Printf("%T, %v\n", &tangoCode, &tangoCode)
}
复制代码

执行上述代码,输出结果如下:

*float64, 0xc000132008
*string, 0xc000116210
*string, 0xc000118180
*int, 0xc00012a060
*string, 0xc000116220
复制代码

Go 的指针 和 C 语言的指针的区别

C 和 C++ 都提供了指针而且功能强大,可以进行指针的转换、偏移以及运算等,其他静态类型语言如 Java 和动态类型语言如 Python 则是将指针屏蔽,不提供指针的概念以及运算等。

Go 中的指针相比 C 和 C++ 中的指针做了很多的限制,有更高的安全性,不涉及到指针的运算、转换和偏移等功能。

make 函数和 new 函数

先来定义一个指针变量,给指针变量的内存地址赋值,并输出其中保存在内存地址中的值

func main() {
   var p *int
   *p = 10
   fmt.Println(*p)
}
复制代码

执行上述代码,输出结果如下:

image.png

这里为什么会报错呢?这里错误信息提示无效的内存地址或者空的指针指向,也就是说没有指定的内存地址来保存 10。

要初始化一个指针变量可以使用 new 函数

func main() {
   var p *int = new(int)
   fmt.Println(*p)
   *p = 10
   fmt.Println(*p)
}
复制代码

执行上述代码,输出结果如下:

0
10
复制代码

new 函数在这里会现申请一个内存空间,然后将内存空间保存的值设置为 int 的默认值既 0,而且 new 函数返回的是一个内存地址。

func main() {
   var p2 *int
   fmt.Println(p2) // 输出结果为:<nil>
}
复制代码

其他类型如 Map、Slice 如果只定义不初始化,也会报错。

func main() {
   var info map[string]string
   info["name"] = "Stark"
   fmt.Println(info)
   var namesSlic []string
   namesSlic[0] = "Thor"
   fmt.Println(namesSlic)
}
复制代码

也可以使用 make 函数来进行初始化,创建内存保存数据,返回一个具体的实例。

func main() {
   var info map[string]string = make(map[string]string)
   fmt.Println(info)
   info["name"] = "Stark"
   fmt.Println(info)
   var namesSlic []string = make([]string, 3)
   fmt.Println(namesSlic)
   namesSlic[0] = "Thor"
   fmt.Println(namesSlic)
}
复制代码

Go 编程 | 连载 11 - 复杂数据类型 Slice 中使用 new 函数创建一个 Slice 实例,因为 new 函数返回的是内存地址,要获取内存地址中保存的实例则需要使用 * 来获取。

make 函数和 new 函数的区别或者使用场景如下:

  • make 和 new 都是用来分配内存的內建函数,且在堆上分配内存,make 即分配内存,也初始化内存;new只是将内存清零,并没有初始化内存。
  • make 返回的还是引用类型(实例)本身;而 new 返回的是指向类型的指针(内存地址)。
  • make 只能用来分配及初始化类型为 slice,map,channel;new 可以分配任意类型的数据。


相关文章
|
15天前
|
数据采集 监控 Java
go语言编程学习
【11月更文挑战第3天】
31 7
|
21天前
|
Unix Linux Go
go进阶编程:Golang中的文件与文件夹操作指南
本文详细介绍了Golang中文件与文件夹的基本操作,包括读取、写入、创建、删除和遍历等。通过示例代码展示了如何使用`os`和`io/ioutil`包进行文件操作,并强调了错误处理、权限控制和路径问题的重要性。适合初学者和有经验的开发者参考。
|
29天前
|
Java 大数据 Go
Go语言:高效并发的编程新星
【10月更文挑战第21】Go语言:高效并发的编程新星
49 7
|
1月前
|
Go 数据处理 调度
Go语言中的并发模型:解锁高效并行编程的秘诀
本文将探讨Go语言中独特的并发模型及其在现代软件开发中的应用。通过深入分析 Goroutines 和 Channels,我们将揭示这一模型如何简化并行编程,提升应用性能,并改变开发者处理并发任务的方式。不同于传统多线程编程,Go的并发方法以其简洁性和高效性脱颖而出,为开发者提供了一种全新的编程范式。
|
1月前
指针(Pointer)的深度理解(2)
指针(Pointer)的深度理解(2)
34 1
|
1月前
|
并行计算 算法 搜索推荐
探索Go语言的高并发编程与性能优化
【10月更文挑战第10天】探索Go语言的高并发编程与性能优化
|
2月前
|
存储 缓存 Go
go语言编程系列(五)
go语言编程系列(五)
|
2月前
|
搜索推荐 Java 编译器
go语言编程系列(四)
go语言编程系列(四)
|
2月前
|
存储 JSON 安全
go语言编程系列(七)
go语言编程系列(七)
|
2月前
|
存储 安全 编译器
go语言编程系列(六)
go语言编程系列(六)
下一篇
无影云桌面