ZetCode

Go 指针

最后修改于 2025 年 5 月 5 日

在本文中,我们将介绍如何在 Golang 语言中使用指针。

在 Go 中,指针 存储的是值的内存地址,而不是值本身。指针的零值为 nil,表示它尚未引用有效的内存位置。与 C 等语言不同,Go 不支持指针算术,这使得指针管理更安全、更可预测。

指针对于高效处理大型数据结构特别有用,因为传递指针可以避免对大型对象的不必要复制。此外,它们还使函数能够修改其自身作用域之外的数据,这对于基于引用的操作至关重要。

var pv *int = &mysum

在此示例中,pv 被声明为指向整数的指针(*int)。& 运算符获取变量 mysum 的内存地址并将其分配给 pv,从而允许间接访问存储的值。

fmt.Println(*pv)

* 运算符用于 解引用 指针,这意味着它会检索所引用内存地址中存储的实际值。通过解引用 pv,我们访问 mysum 存储的值。

通过使用指针,Go 实现了高效的内存使用,并允许函数直接处理变量而不是副本,从而在某些情况下提高了性能。

Go 指针示例

以下是一个简单的 Go 指针示例。

simple.go
package main

import "fmt"

func main() {

    var count int = 4
    fmt.Println(count)

    var pv = &count
    *pv = 3
    fmt.Println(pv)
    fmt.Println(*pv)

    var pv2 *int = &count
    *pv = 2
    fmt.Println(pv2)
    fmt.Println(*pv2)

    pv3 := &count
    *pv = 1
    fmt.Println(pv3)
    fmt.Println(*pv3)
}

我们定义了一个 count 整数变量。我们使用三种不同的形式创建了三个指向该变量的指针。

var count int = 4

我们创建了 count 变量。

var pv = &count

我们创建了一个指向 count 变量的指针。

*pv = 3

通过指针解引用,我们修改了 count 的值。

fmt.Println(pv)
fmt.Println(*pv)

我们打印 pv 指针的地址和值。

$ go run simple.go 
4
0xc0000140f8
3
0xc0000140f8
2
0xc0000140f8
1

Go 指针修改

指针可用于修改其定义函数外部的变量。

modify.go
package main

import "fmt"

func modify(pv *int) {

    *pv = 11
}

func main() {

    var count int = 10
    fmt.Println(count)

    modify(&count)
    fmt.Println(count)
}

main 函数内部,我们定义了 count 变量。modify 函数将指针作为参数。我们可以使用它来修改 main 函数外部的 count 变量。默认情况下,Go 中的函数按值传递变量。

$ go run modify.go 
10
11

Go 指向结构体的指针

在 Go 中,指针经常与结构体一起使用。

pstruct.go
package main

import "fmt"

type User struct {
    name       string
    occupation string
}

func modify(pu *User) {

    pu.name = "Robert Roe"
    pu.occupation = "driver"
}

func main() {

    u := User{"John Doe", "gardener"}
    fmt.Println(u)

    modify(&u)

    fmt.Println(u)
}

我们有一个 User 结构体。我们通过指针在 modify 函数中修改了该结构体。

pu.name = "Robert Roe"

pu.name(*pu).name 相同。

$ go run pstruct.go 
{John Doe gardener}
{Robert Roe driver}

使用 new 关键字的 Go 指针

new 关键字接受一个类型作为参数,分配足够的内存来容纳该类型的值,并返回其指针。

newkey.go
package main

import (
    "fmt"
    "reflect"
)

type User struct {
    name       string
    occupation string
}

func main() {

    var pu *User = new(User)
    fmt.Println(pu)
    fmt.Println(reflect.TypeOf(pu))

    pu.name = "Robert Roe"
    pu.occupation = "accountant"
    fmt.Println(pu)
}

在代码示例中,我们使用 new 关键字创建了一个用户。

$ go run newkey.go 
&{ }
*main.User
&{Robert Roe accountant}

Go 指向指针的指针

一个指针可以指向另一个指针。要解引用此类指针的值,我们使用 ** 字符。

pointer2pointer.go
package main

import "fmt"

func main() {

    var a = 7
    var p = &a
    var pp = &p

    fmt.Println(a)
    fmt.Println(&a)

    fmt.Println("--------------------")

    fmt.Println(p)
    fmt.Println(&p)

    fmt.Println("--------------------")

    fmt.Println(pp)
    fmt.Println(&pp)

    fmt.Println("--------------------")

    fmt.Println(*pp)
    fmt.Println(**pp)
}

该示例创建了一个指向另一个指针 p 的指针 pp

$ go run pointer2pointer.go 
7
0xc0000140f8
--------------------
0xc0000140f8
0xc00000e028
--------------------
0xc00000e028
0xc00000e030
--------------------
0xc0000140f8
7

来源

The Go Programming Language Specification

在本文中,我们介绍了 Go 指针。

作者

我叫 Jan Bodnar,是一位充满激情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在教授编程方面拥有十多年的经验。

列出所有 Go 教程