Go 语言的指针是变量的内存地址。指针允许我们直接操作变量的内存位置,进而修改数据的值。在 Go 中,指针是非常重要的概念,尤其在处理大型数据结构和性能优化时非常有用。Go 语言通过指针避免了不必要的内存复制,同时提供了更加直接的内存访问方式。


📖 目录

  1. 指针的定义
  2. 指针的声明与初始化
  3. 指针的使用
  4. 指针的解引用
  5. 指针与数组
  6. 指针与切片
  7. 指针与结构体
  8. Go 中的指针传递
  9. 指针的零值
  10. 总结
  11. 参考资料

1. 指针的定义

指针是一个存储其他变量内存地址的变量。它不是变量本身的值,而是指向该值的地址。指针的类型与它所指向的变量的类型相同。

示例:

package main

import "fmt"

func main() {
    var a int = 58    // 定义一个整数变量
    var ptr *int      // 定义一个指向整数的指针变量

    ptr = &a          // 使用 `&` 取地址,ptr 存储 a 的地址

    fmt.Println(ptr)   // 输出指针地址
    fmt.Println(*ptr)  // 解引用,输出 a 的值: 58
}

输出:

0xc000016098  // ptr 存储的是变量 a 的内存地址(值可能不同)
58            // 解引用 ptr,输出 a 的值


2. 指针的声明与初始化

在 Go 中,指针声明的语法格式为:

var 指针变量 *数据类型

  • * 表示这是一个指向该数据类型的指针。
  • & 是取地址符号,用于获取变量的内存地址。

示例:

package main

import "fmt"

func main() {
    var a int = 42
    var ptr *int = &a  // 获取变量 a 的地址,并将地址赋值给 ptr

    fmt.Println(ptr)    // 输出指针的地址
    fmt.Println(*ptr)   // 输出 ptr 指向的值,即 a 的值
}


3. 指针的使用

指针的基本作用是通过内存地址访问和修改变量的值。可以使用 & 操作符获取变量的地址,使用 * 操作符解引用指针。

示例:

package main

import "fmt"

func main() {
    var a int = 5
    var ptr *int = &a  // 获取 a 的地址

    fmt.Println("Address of a:", ptr)    // 输出 a 的地址
    fmt.Println("Value of a through ptr:", *ptr)  // 输出 a 的值,通过 ptr 访问

    *ptr = 10  // 使用指针修改 a 的值
    fmt.Println("Updated value of a:", a)  // 输出更新后的 a 值
}

输出:

Address of a: 0xc0000160b0
Value of a through ptr: 5
Updated value of a: 10


4. 指针的解引用

解引用是通过指针访问指向的变量值的过程。通过解引用,能够读取或修改指针指向的内存地址的值。

示例:

package main

import "fmt"

func main() {
    var a int = 25
    var ptr *int = &a  // 获取 a 的地址

    fmt.Println(*ptr)  // 解引用指针,输出 a 的值
    *ptr = 50          // 修改指针指向的值,即修改 a
    fmt.Println(a)     // 输出修改后的 a 值
}

输出:

25
50


5. 指针与数组

指针在 Go 语言中可以指向数组的元素,或者可以指向整个数组。指针和数组配合使用时,需要特别注意数组的传递方式。

示例:

package main

import "fmt"

func main() {
    arr := [3]int{1, 2, 3}
    ptr := &arr[0]  // 指向数组的第一个元素

    fmt.Println(*ptr)  // 输出数组的第一个元素: 1

    // 修改数组的第一个元素
    *ptr = 10
    fmt.Println(arr)   // 输出更新后的数组: [10 2 3]
}


6. 指针与切片

切片本质上是一个指针,指向数组的一个部分。因此,我们可以通过指针操作切片的内容。

示例:

package main

import "fmt"

func main() {
    arr := []int{1, 2, 3}
    ptr := &arr[0]  // 指向切片的第一个元素

    fmt.Println(*ptr)  // 输出: 1

    // 修改切片的第一个元素
    *ptr = 10
    fmt.Println(arr)   // 输出: [10 2 3]
}


7. 指针与结构体

指针可以指向结构体,结构体指针可以让我们高效地传递和修改结构体的数据。

示例:

package main

import "fmt"

// 定义一个结构体
type Person struct {
    Name string
    Age  int
}

func main() {
    p := Person{"Alice", 25}
    ptr := &p  // 获取结构体的指针

    fmt.Println(ptr.Name)  // 输出结构体字段 Name: Alice
    ptr.Age = 30           // 修改结构体字段 Age
    fmt.Println(p.Age)     // 输出修改后的 Age: 30
}


8. Go 中的指针传递

Go 语言中的函数参数传递是按值传递的。如果希望修改传入函数的值,可以传递指针。

示例:

package main

import "fmt"

func modifyValue(ptr *int) {
    *ptr = 100
}

func main() {
    a := 10
    modifyValue(&a)  // 传递 a 的地址
    fmt.Println(a)    // 输出: 100
}

在上述示例中,通过传递指针,我们能够在函数中修改变量 a 的值。


9. 指针的零值

Go 中的指针的零值是 nil,这意味着指针没有指向任何有效的内存地址。

示例:

package main

import "fmt"

func main() {
    var ptr *int  // 默认值为 nil
    fmt.Println(ptr)  // 输出: <nil>
}


10. 总结

  • 指针存储其他变量的内存地址。
  • Go 使用 & 来获取变量的地址,使用 * 来解引用指针。
  • 指针可以用来直接修改变量的值,避免值传递带来的额外内存开销。
  • Go 中的指针操作简单,且与其他语言如 C/C++ 有所不同(例如 Go 没有指针运算)。
  • 使用指针时需要注意空指针(nil)的处理。

11. 参考资料


Go 语言中的指针允许程序员高效地操作内存,并在需要直接访问变量内存时提供更强的控制力。理解指针和它们的使用是 Go 编程中不可忽视的重要部分。