了解 Go 中的指针
目录
-
在 Go 中导入包 -
理解 Go 中包的可见性 -
如何在 Go 中编写条件语句 -
如何在 Go 中编写 Switch 语句 -
如何在 Go 中构造 for 循环 -
在循环中使用 Break 和 Continue -
如何在 Go 中定义并调用函数 -
如何在 Go 中使用可变参数函数 -
了解 Go 中的 defer -
了解 Go 中的 init -
用构建标签定制 Go 二进制文件 -
了解 Go 中的指针 -
在 Go 中定义结构体 -
在 Go 中定义方法 -
如何构建和安装 Go 程序 -
如何在 Go 中使用结构体标签 -
如何在 Go 使用 interface -
在不同的操作系统和架构编译 Go 应用 -
用 ldflags 设置 Go 应用程序的版本信息 -
在 Go 里面如何使用 Flag 包
简介
当你用 Go 编写软件时,你会编写函数和方法。你将数据作为 参数 传递给这些函数。有时,函数会需要一个数据的本地拷贝,你希望原始数据保持不变。例如,如果你是一家银行,你有一个函数可以根据用户选择的储蓄计划来显示他们的余额变化,你不想在客户选择计划之前改变他们的实际余额,而只想用它来做计算。这被称为 按值传递,因为你是在向函数发送变量的值,而不是变量本身。
其他时候,你可能希望函数能够改变原始变量中的数据。例如,当银行客户向其账户存款时,你希望存款函数能够访问实际的余额,而不是一个副本。在这种情况下,你不需要向函数发送实际数据, 而只需要告诉函数数据在内存中的位置。一个叫做 指针 的数据类型持有数据的内存地址,但不是数据本身。内存地址告诉函数在哪里可以找到数据,而不是数据的值。你可以把指针传给函数而不是实际的数据,然后函数就可以在原地改变原始变量的值。这被称为 通过引用传递,因为变量的值并没有传递给函数,而是传递了它指向的位置。
在这篇文章中,你将创建并使用指针来分享对一个变量的内存空间的访问。
定义和使用指针
当你使用一个指向变量的指针时,有几个不同的语法元素你需要了解。第一个是与号(&
)的使用。如果你在一个变量名称前面加一个与号,你就说明你想获得 地址,或者说是该变量的一个指针。第二个语法元素是使用星号(*
)或 引用 操作符。当你声明一个指针变量时,你在变量名后面加上指针指向的变量类型,前面加一个*
,像这样:
var myPointer *int32 = &someint
这将创建 myPointer
作为一个指向 int32
变量的指针,并以 someint
的地址初始化该指针。指针实际上并不包含一个 int32
,而只是一个地址。
让我们来看看一个指向 string
的指针。下面的代码既声明了一个字符串的值,又声明了一个指向字符串的指针:
package main
import "fmt"
func main() {
var creature string = "shark"
var pointer *string = &creature
fmt.Println("creature =", creature)
fmt.Println("pointer =", pointer)
}
用以下命令运行该程序:
go run main.go
当你运行程序时,它将打印出变量的值,以及该变量的存储地址(指针地址)。内存地址是一个十六进制的数字,并不是为了让人看懂。在实践中,你可能永远不会输出内存地址来查看它。我们给你看是为了说明问题。因为每个程序运行时都是在自己的内存空间中创建的,所以每次运行时指针的值都会不同,也会与下面显示的输出不同:
creature = shark
pointer = 0xc0000721e0
我们定义的第一个变量名为 creature
,并将其设置为一个 string
,其值为 shark
。然后我们创建了另一个名为 pointer
的变量。这一次,我们将 pointer
变量的值设置为 creature
变量的地址。我们通过使用与号(&
)符号将一个值的地址存储在一个变量中。这意味着 pointer
变量存储的是 creature
变量的 地址 ,而不是实际值。 这就是为什么当我们打印出 pointer
的值时,我们收到的值是 0xc0000721e0
,这是 creature
变量目前在计算机内存中的地址。
如果你想打印出 pointer
变量所指向的变量的值,你需要 解引用 该变量。下面的代码使用 *
操作符来解除对 pointer
变量的引用并检索其值。