GO语言基础教程(95)Go指针的使用方法之声明指针变量:Go指针魔法棒!小白也能玩转的「内存地址」通关攻略

一、 为什么指针总让人“血压飙升”?

很多新手听到“指针”二字就头大,仿佛回到被C++指针支配的校园时代。但Go的指针其实是个“温和版刺客”——能直接操作内存,却不会让你随便搞崩系统

想象你搬家时有两种选择:

  • 传值:把家具全部复制一份给朋友(费时费内存)
  • 传指针:直接把新家地址发给朋友(高效省资源)

Go指针就是那个“地址纸条”,让你用最小代价操控数据老巢。接下来咱们用三分钟,把这张纸条的玩法摸透!


二、 指针基础:从「宇宙符号」*&说起

1. 两个核心操作符
  • &(取址符):好比查户口,获取变量在内存的住址
  • *(解引用符):好比用钥匙开门,直接访问地址里的值
2. 声明指针的三种姿势

姿势一:标准宣言

var ptr *int  // 声明一个指向int类型的指针

这时的ptrnil,就像一张没写地址的空纸条。

姿势二:就地取材

age := 25
ptr := &age  // 把age的地址赋给ptr

此时ptr指向age的家,*ptr能掏出值25

姿势三:new()函数造房

ptr := new(int)  // 直接分配一块int内存,返回指针
*ptr = 30        // 给这个地址赋值

new()相当于地产开发商,直接给你个毛坯房地址。


三、 完整示例:指针实战情景剧

下面我们演一出《指针变形记》,注意看代码注释:

package main

import "fmt"

func main() {
    // 场景1:基本操作 - 跟踪变量豪宅
    house := "别墅"
    var address *string = &house  // 获取豪宅地址
    
    fmt.Printf("房子类型:%T,值:%s\n", house, house)           // 输出:房子类型:string,值:别墅
    fmt.Printf("地址类型:%T,地址值:%p\n", address, address) // 输出地址(十六进制)
    fmt.Printf("通过地址看房子:%s\n", *address)               // 输出:别墅
    
    // 场景2:修改门牌 - 指针改变原值
    *address = "海景大平层"
    fmt.Println("翻修后的房子:", house) // 输出:海景大平层
    
    // 场景3:空指针警戒区 - 别敲NULL的门!
    var emptyPtr *string
    if emptyPtr == nil {
        fmt.Println("空指针警告!别直接解引用") 
        // *emptyPtr = "炸弹"  // 放开这行会panic!
    }
    
    // 场景4:函数传参性价比之战
    price := 100
    doubleFail(price)
    fmt.Println("传值操作后:", price) // 还是100,原值未变
    
    doubleReal(&price)             
    fmt.Println("传指针操作后:", price) // 变成200,直捣老巢
}

// 传值:收到的是副本
func doubleFail(money int) {
    money *= 2
}

// 传指针:拿到保险箱钥匙
func doubleReal(money *int) {
    *money *= 2  // 修改原值
}

运行结果

房子类型:string,值:别墅
地址类型:*string,地址值:0xc000010050
通过地址看房子:别墅
翻修后的房子: 海景大平层
空指针警告!别直接解引用
传值操作后: 100
传指针操作后: 200

四、 避坑指南:指针玩家的自我修养

坑1:空指针解引用(经典闪退)
var p *int
fmt.Println(*p) // panic: runtime error!

防御策略

if p != nil {
    fmt.Println(*p) // 安全操作
}
坑2:指针越界(小心隔壁老王)

Go的内存安全机制会阻止越界访问,但别故意试探编译器底线。

坑3:函数内返回局部变量指针
func danger() *int {
    num := 10
    return &num  // 编译器其实会逃逸分析,但别依赖!
}

虽然Go有逃逸分析保底,但逻辑上这仍是危险操作。


五、 进阶技巧:当指针遇上结构体和切片

1. 结构体指针:直击对象软肋
type Player struct {
    Name string
    Level int
}

p := &Player{"菜鸟", 1}
p.Level = 99  // 等价于 (*p).Level,Go自动解引用甜点
fmt.Println(p.Name, "秒变满级大佬") 
2. 切片的小秘密

切片本身是“胖指针”,包含数组指针+长度+容量:

data := []int{1,2,3}
slicePtr := &data[0]  // 获取底层数组首地址

但直接操作切片指针较少见,因为切片已自带引用语义。


六、 总结:指针使用心法

  1. 声明三式var p *Tp := &vp := new(T)
  2. 核心口诀&取址,*取值,nil指针别解引用
  3. 使用场景
    • 大结构体传参避免复制
    • 需要修改原值
    • 实现链表/树等数据结构
  1. Go特色:无指针运算,安全系数++

最后送个彩蛋:尝试用指针实现一个「变量交换器」,彻底告别临时变量!指针不是洪水猛兽,而是你代码库里的空间魔术师。多写多练,让内存操作成为你的超能力!


附录:思考题

  • 如何用指针实现一个精简版链表?
  • 函数返回指针时,编译器背后做了哪些优化?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

值引力

持续创作,多谢支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值