跳到主要内容

Go 指针

提示
  1. 指针的定义:Go 中的指针允许我们直接操作内存地址,可以访问和修改内存中的变量值。
  2. 指针变量的使用:在 Go 中,指针变量用于存储内存地址,例如 var ptr *int = &num 表示存储 num 变量的内存地址。
  3. 通过指针获取值:使用 * 运算符来访问指针指向的内存地址中的值,例如 fmt.Println(*ptr) 可以打印 ptr 指向的变量的值。

Go 编程中的指针允许我们直接处理内存地址。例如,我们可以使用指针访问和修改内存中变量的值。

在学习指针之前,让我们首先了解 Go 语言中的内存地址。

内存地址

当我们创建一个变量时,会为该变量分配一个内存地址以存储其值。

在 Go 中,我们可以使用 & 运算符来访问内存地址。例如,

// 展示内存地址如何工作的程序

package main
import "fmt"

func main() {

var num int = 5
// 打印变量中存储的值
fmt.Println("变量值:", num)

// 打印变量的地址
fmt.Println("内存地址:", &num)

}

输出

变量值: 5
内存地址: 0xc000018030

在上述示例中,我们创建了一个值为 5 的 num 变量。注意打印语句

fmt.Println("内存地址:", &num)

这里,&num 访问了存储 num 变量的内存地址。

Go 指针变量

在 Go 中,我们使用指针变量来存储内存地址。例如,

var num int = 5

// 创建指针变量
var ptr *int = &num

这里,我们创建了一个名为 ptr 的指针变量,它存储了 num 变量的内存地址。

*int 表示指针变量是 int 类型(存储 int 类型变量的内存地址)。

我们也可以创建其他类型的指针变量。例如,

// 字符串类型的指针变量
var ptr1 *string

// 双精度浮点类型的指针变量
var ptr2 *float32

现在让我们看一个指针的工作示例。

示例:指针变量

我们可以将变量的内存地址赋给一个指针变量。例如,

// 将内存地址赋给指针的程序

package main
import "fmt"

func main() {

var name = "John"
var ptr *string

// 将 name 的内存地址赋给指针
ptr = &name

fmt.Println("指针的值是", ptr)
fmt.Println("变量的地址", &name)

}

输出

指针的值是 0xc00007c1c0
变量的地址 0xc00007c1c0

在上面的示例中,我们创建了一个类型为 string 的指针变量 ptr。这里,指针变量和 name 变量的地址是相同的。

这是因为指针 ptr 存储了 name 变量的内存地址。

ptr = &name

在 Golang 中获取指针指向的值

我们使用 * 运算符来访问指针指向的内存地址中的值。例如,

// 获取指针指向的值的程序

package main
import "fmt"

func main() {

var name = "John"
var ptr *string

ptr = &name

// 使用 * 来获取 ptr 指向的值
fmt.Println(*ptr) // John

}

这里,我们使用了 *ptr 来访问指针指向的内存地址中存储的值。

由于指针存储了 name 变量的内存地址,我们得到了 "John" 作为输出。

注意: 在上述示例中,ptr 是一个指针,而不是 *ptr。你不能也不应该做类似 *ptr = &name 的事情。

* 被称为解引用运算符(在处理指针时)。它作用于一个指针,并给出该指针所存储的值。

示例:Go 指针的工作原

package main
import "fmt"

func main() {
var num int
var ptr *int

num = 22
fmt.Println("num 的地址:",&num)
fmt.Println("num 的值:",num)

ptr = &num
fmt.Println("\nptr 指针的地址:",ptr)
fmt.Println("ptr 指针的内容:",*ptr)

num = 11
fmt.Println("\nptr 指针的地址:",ptr)
fmt.Println("ptr 指针的内容:",*ptr)

*ptr = 2
fmt.Println("\nnum 的地址:",&num)
fmt.Println("num 的值:",num)
}

输出

num 的地址: 0xc000090020
num 的值: 22

ptr 指针的地址: 0xc000090020
ptr 指针的内容: 22

ptr 指针的地址: 0xc000090020
ptr 指针的内容: 11

num 的地址: 0xc000090020
num 的值: 2

解释:Go 指针的工作原理

1. 声明变量

var num int
var ptr *int

声明了指针变量和普通变量

这里,我们创建了一个整数类型的指针变量 ptr 和一个普通变量 num。最初这两个变量都没有初始化,因此指针 ptr 不指向任何地址。

2. 给普通变量赋值

num = 22

给普通变量赋值。

这将 22 赋给了变量 num。也就是说,22 被存储在变量 num 的内存位置中。

3. 给指针赋地址

ptr = &num

将普通变量的地址赋给指针变量

这将变量 num 的地址赋给了指针 ptr。

4. 改变变量的值

num = 11

改变变量的值。

这将 11 赋给了变量 num。

5. 使用指针改变值

*ptr = 2

使用指针解引用运算符改变变量的值。

这将指针 ptr 指向的内存位置的值改为 2

常见问题

Go 中的空指针

当我们声明一个指针变量但不初始化时,指针的值总是 nil。例如,

// 展示空指针的程序

package main
import "fmt"

func main() {
// 声明一个指针变量
var ptr *int

fmt.Println("指针的值:", ptr)

}

输出

指针的值: <nil>

这里,指针 ptr 未初始化,因此它不指向任何地址。因此,指针的默认值总是 nil。

使用 Golang 的 new() 创建指针

我们也可以使用 new() 函数在 Go 中创建指针。例如,

// 使用 new() 函数创建指针的程序

package main
import "fmt"

func main() {

// 使用 new() 创建指针
var ptr = new(int)

*ptr = 20

fmt.Println(ptr) // 0xc000016058
fmt.Println(*ptr) // 20

}

这里,在 var ptr = new(int) 这一行中,变量 ptr 成为了 int 类型的指针。

当我们将 *ptr 赋为 20 时,ptr 在内存位置的值变为 20

不使用 * 运算符创建指针

在 Go 中,我们也可以不使用 * 运算符来创建指针变量。例如,

package main
import "fmt"

func main() {

var name = "John"

// 不使用 * 创建指针
var ptr = &name

fmt.Println("ptr 的值:", ptr)
fmt.Println("name 的地址:", &name)

}

输出

ptr 的值: 0xc0000101e0
name 的地址: 0xc0000101e0

在这里,我们直接将 &name(name 的地址)赋给了 ptr 变量。

在这种情况下,该变量是一个指针变量,尽管我们没有使用 * 运算符。