首页 > 后端开发 > Golang > 正文

Go语言中指针操作符*与取地址符&的全面解析

聖光之護
发布: 2025-07-18 11:00:03
原创
1011人浏览过

Go语言中指针操作符*与取地址符&的全面解析

本文深入探讨Go语言中*和&这两个核心操作符的作用。&用于获取变量的内存地址,生成一个指向该变量的指针;而*则用于声明指针类型、对指针进行解引用以访问其指向的值,以及通过指针间接修改变量的值。理解它们对于掌握Go的内存管理和数据传递机制至关重要,尤其是在函数参数传递和结构体操作中。

go语言中,指针是一个核心概念,它允许程序直接操作内存地址,从而实现更灵活的数据管理和高效的程序设计。理解*(星号)和&(取地址符)这两个操作符是掌握go语言指针的关键。

1. & 操作符:取地址(Address-of Operator)

& 操作符用于获取一个变量的内存地址。当应用于一个变量时,它会返回该变量在内存中的地址,这个地址就是一个指向该变量类型的新指针。

语法: &variable

示例:

package main

import "fmt"

func main() {
    value := 100
    ptr := &value // ptr 现在是一个指向 value 变量的指针
    fmt.Printf("变量 value 的值:%d\n", value)
    fmt.Printf("变量 value 的内存地址:%p\n", ptr) // %p 用于打印指针地址
}
登录后复制

在上述示例中,ptr 变量存储的不是 100 这个值,而是 value 变量在内存中的具体位置。

立即学习go语言免费学习笔记(深入)”;

2. * 操作符:指针的声明、解引用与间接赋值

* 操作符在Go语言中扮演了多重角色,其具体含义取决于它出现的位置。

2.1 指针类型声明(Pointer Type Declaration)

当 * 紧跟在一个类型前面时(例如 *int, *string),它表示声明一个指向该类型数据的指针。这意味着这个变量将存储一个内存地址,而这个地址指向的是指定类型的数据。

语法: var variableName *Type

示例:

package main

import "fmt"

func main() {
    var p *int // 声明 p 是一个指向 int 类型数据的指针
    fmt.Printf("p 的零值(未初始化):%v\n", p) // 指针的零值是 nil
}
登录后复制

2.2 指针解引用(Dereferencing)

当 * 放置在一个已声明的指针变量前面时,它被称为解引用操作符。解引用操作用于访问或获取指针所指向的内存地址中存储的实际值。

语法: *pointerVariable

美图云修
美图云修

商业级AI影像处理工具

美图云修 61
查看详情 美图云修

示例:

package main

import "fmt"

func main() {
    value := 200
    ptr := &value // ptr 指向 value 的地址
    fmt.Printf("通过 ptr 解引用获取 value 的值:%d\n", *ptr) // *ptr 获取 ptr 指向的值
}
登录后复制

2.3 指针间接赋值(Indirect Assignment)

通过解引用操作符,我们不仅可以读取指针指向的值,还可以修改该值。当 *pointerVariable 出现在赋值语句的左侧时,它表示修改指针所指向内存地址中的值。

语法: *pointerVariable = newValue

示例:

package main

import "fmt"

func main() {
    num := 300
    ptr := &num // ptr 指向 num 的地址
    fmt.Printf("修改前 num 的值:%d\n", num)

    *ptr = 400 // 通过 ptr 间接修改 num 的值
    fmt.Printf("修改后 num 的值:%d\n", num)
}
登录后复制

3. 综合示例分析

为了更深入地理解 & 和 * 的协同工作,我们来分析一个典型的代码片段:

package main

import (
    "fmt"
    "os"
)

func main() {
    s := "hello" // 声明并初始化字符串变量 s
    if s[1] != 'e' { // 检查字符串 s 的第二个字符是否为 'e'
        os.Exit(1) // 如果不是,则退出程序
    }
    fmt.Printf("s 初始值: %s, 地址: %p\n", s, &s)

    s = "good bye" // 重新赋值 s
    fmt.Printf("s 重新赋值后: %s, 地址: %p\n", s, &s)

    var p *string = &s // 声明一个字符串指针 p,并用 s 的地址初始化它
    fmt.Printf("指针 p 的值 (s 的地址): %p\n", p)
    fmt.Printf("通过指针 p 解引用得到的值: %s\n", *p)

    *p = "ciao" // 通过指针 p 间接修改 s 的值
    fmt.Printf("通过指针 p 修改后 s 的值: %s\n", s)
    fmt.Printf("通过指针 p 修改后,通过 p 解引用得到的值: %s\n", *p)
}
登录后复制

分析过程:

  1. s := "hello":变量 s 被创建并赋值为 "hello"。
  2. s = "good bye":s 的值被更新为 "good bye"。此时 s 的内存地址保持不变,但其内容已更改。
  3. var p *string = &s:
    • &s:获取变量 s 的内存地址。
    • *string:声明 p 是一个指向 string 类型的指针。
    • =:将 s 的内存地址赋值给 p。现在,p 指向 s 所在的内存位置。
  4. *p = "ciao":
    • *p:解引用 p,表示访问 p 所指向的内存位置(即 s 的内存位置)。
    • =:将 "ciao" 这个字符串赋值到 p 所指向的内存位置。这意味着 s 的值被间接修改为 "ciao"。

运行此代码,您会观察到 s 的值最终变为 "ciao",这证明了通过指针可以实现对原始变量的间接修改。

4. Go语言中的“引用”与“值传递”

Go语言中所有函数参数的传递都是值传递(pass by value)。这意味着当您将一个变量作为参数传递给函数时,函数会接收到该变量的一个副本。对副本的任何修改都不会影响原始变量。

然而,当您传递一个指针的值时,函数接收到的是原始变量的内存地址的副本。虽然这个地址本身是一个副本,但它指向的仍然是原始变量在内存中的位置。因此,通过这个指针副本解引用并修改其指向的值,就能够影响到原始变量。这在效果上类似于其他语言中的“引用传递”,但本质上仍是值传递——只是传递的是一个地址值。

package main

import "fmt"

func modifyValue(x int) { // 值传递,x 是 num 的副本
    x = 20
}

func modifyValueByPointer(ptr *int) { // 值传递,ptr 是 &num 的副本
    *ptr = 20 // 通过指针修改 num
}

func main() {
    num := 10
    fmt.Println("初始值:", num) // 10

    modifyValue(num)
    fmt.Println("值传递后:", num) // 10 (未改变)

    modifyValueByPointer(&num)
    fmt.Println("指针传递后:", num) // 20 (已改变)
}
登录后复制

5. 指针的应用场景与注意事项

5.1 典型应用场景

  • 修改函数外部变量:如上例所示,当需要在函数内部修改函数外部的变量时,传递变量的指针是标准做法。
  • 避免大数据结构复制:当结构体或数组非常大时,将其作为参数传递会导致整个数据结构的复制,消耗大量内存和时间。传递其指针可以避免这种开销,提高性能。
  • 实现链表、树等数据结构:这些数据结构天然依赖于节点间的指针连接。
  • 方法接收者:Go语言中,方法的接收者可以是值类型也可以是指针类型。使用指针接收者可以修改接收者实例的字段。

5.2 注意事项

  • 零值指针(nil):未初始化的指针变量的零值是 nil。尝试解引用 nil 指针会导致运行时错误(panic)。在使用指针前,务必确保其已被正确初始化或检查是否为 nil。
  • Go不支持指针算术:与C/C++不同,Go语言不允许对指针进行加减运算来访问相邻内存地址。这是为了提高内存安全性和代码可读性
  • 垃圾回收:Go语言拥有自动垃圾回收机制,开发者无需手动管理内存的分配和释放。当一个内存地址不再有任何指针指向它时,垃圾回收器会在适当的时候自动回收这块内存。

总结

& 和 * 是Go语言中操作指针的两个基本且强大的操作符。& 用于获取变量的内存地址,生成一个指针;而 * 则用于声明指针类型、解引用指针以访问其指向的值,以及通过指针间接修改变量的值。理解并熟练运用它们,是编写高效、安全Go程序的基础。掌握指针不仅能让您更深入地理解Go的内存模型,也能帮助您在特定场景下优化程序性能和实现复杂的数据结构。

以上就是Go语言中指针操作符*与取地址符&的全面解析的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号