简单了解指针和指针本身
扫描二维码
随时随地手机看文章
当我们有一个指针时,我们通常需要获取指针指向的值的反射对象。这时,我们可以使用 `reflect.Value` 的 `Elem()` 方法来获取指针指向的元素的反射值。`Elem()` 方法会对指针进行解引用,返回指针指向的值的 `reflect.Value`。如果 `reflect.Value` 本身不是指针,调用 `Elem()` 会导致 panic。
1. 指针本身的反射值
var num int = 42
ptr := &num // ptr 是一个指向 num 的指针
// 获取指针的反射值(指针本身)
valPtr := reflect.ValueOf(ptr)
fmt.Println(valPtr.Kind()) // 输出: ptr
这里 valPtr 表示的是指针变量 ptr 的反射值,其类型为 reflect.Ptr(指针类型)。
2. 获取指针指向的值
如果需要操作指针指向的实际数据(如 num),需通过 Elem() 方法解引用:
// 解引用指针,获取其指向的值
valNum := valPtr.Elem()
fmt.Println(valNum.Kind()) // 输出: int
fmt.Println(valNum.Int()) // 输出: 42
valNum 现在表示指针指向的 int 值,可直接修改:
valNum.SetInt(100) // 修改原始数据
fmt.Println(num) // 输出: 100
“获取指针对应的反射值”时,可能有两种含义:
获取指针本身的反射值。
获取指针指向的值的反射值。
在 Go 的反射中,通常通过 `reflect.ValueOf(ptr)` 得到指针的反射值,然后通过调用其 `Elem()` 来获取指针指向的值的反射值。
3.市导航的比喻
想象你在一个城市里:
数据 = 一栋实际存在的房子(例如:"阳光小区3栋")
指针 = 写着房子地址的导航卡片(例如:卡片上写着"阳光小区3栋")
指针本身 = 你手里拿着的这张导航卡片
4.关键区别
指针指向的值 实际的房子 *ptr 解引用后的值 直接修改房子属性
指针本身 你手中的导航卡片 ptr 指针变量 修改卡片上的地址
指针的值 卡片上写的地址文字 指针的内存地址(如0xc0000...) 查看卡片内容
Go代码示例
package main
import (
"fmt"
"reflect"
)
func main() {
// 1. 创建一栋房子(实际数据)
house := "阳光小区3栋"
// 2. 创建导航卡片(指针)
card := &house // card是指向房子的指针
// 3. 获取卡片本身的反射对象(不是房子!)
cardReflect := reflect.ValueOf(card)
fmt.Println("=== 导航卡片信息 ===")
fmt.Printf("卡片类型: %v\n", cardReflect.Type()) // *string
fmt.Printf("卡片种类: %v\n", cardReflect.Kind()) // ptr
fmt.Printf("卡片内容: %p\n", card) // 内存地址(0x...)
// 4. 通过卡片找到实际房子
houseReflect := cardReflect.Elem()
fmt.Println("\n=== 房子信息 ===")
fmt.Printf("房子类型: %v\n", houseReflect.Type()) // string
fmt.Printf("房子值: %v\n", houseReflect.String()) // 阳光小区3栋
// 5. 修改房子(通过卡片导航)
houseReflect.SetString("明月花园8单元")
fmt.Println("\n修改后的房子:", house) // 明月花园8单元
// 6. 修改卡片本身(不改变房子)
newHouse := "星河湾12座"
cardReflect.Set(reflect.ValueOf(&newHouse)) // 让卡片指向新地址
fmt.Println("\n=== 卡片重定向后 ===")
fmt.Println("卡片指向:", *card) // 星河湾12座
fmt.Println("原房子:", house) // 明月花园8单元(未改变)
}