golang的CanSet/CanAddr属性研究

先看代码:

 

package main

import (
"fmt"
"reflect"
)


func main() {
var n = 33
var pn = &n
var ppn = &pn
var pn2 *int = nil

// 指针是不能set的,指针指向的元素可以set
fmt.Println("reflect.ValueOf(n).CanSet():", reflect.ValueOf(n).CanSet())
fmt.Println("reflect.ValueOf(pn).CanSet():", reflect.ValueOf(pn).CanSet())
fmt.Println("reflect.ValueOf(pn2).CanSet():", reflect.ValueOf(pn2).CanSet())
fmt.Println("reflect.ValueOf(ppn).CanSet():", reflect.ValueOf(ppn).CanSet())

// 指针是不能set的,指针指向的元素可以set
//fmt.Println("reflect.ValueOf(n).Elem().CanSet():", reflect.ValueOf(n).Elem().CanSet()) // 值没有elem
fmt.Println("reflect.ValueOf(pn).Elem().CanSet():", reflect.ValueOf(pn).Elem().CanSet())
fmt.Println("reflect.ValueOf(pn2).Elem().CanSet():", reflect.ValueOf(pn2).Elem().CanSet())
fmt.Println("reflect.ValueOf(ppn).Elem().CanSet():", reflect.ValueOf(ppn).Elem().CanSet())



// 指针是不能set的,指针指向的元素可以set
fmt.Println("reflect.ValueOf(n).CanAddr():", reflect.ValueOf(n).CanAddr())
fmt.Println("reflect.ValueOf(pn).CanAddr():", reflect.ValueOf(pn).CanAddr())
fmt.Println("reflect.ValueOf(pn2).CanAddr():", reflect.ValueOf(pn2).CanAddr())
fmt.Println("reflect.ValueOf(ppn).CanAddr():", reflect.ValueOf(ppn).CanAddr())

// 指针是不能set的,指针指向的元素可以set
// fmt.Println("reflect.ValueOf(n).Elem().CanAddr():", reflect.ValueOf(n).Elem().CanAddr())// 值没有elem
fmt.Println("reflect.ValueOf(pn).Elem().CanAddr():", reflect.ValueOf(pn).Elem().CanAddr())
fmt.Println("reflect.ValueOf(pn2).Elem().CanAddr():", reflect.ValueOf(pn2).Elem().CanAddr())
fmt.Println("reflect.ValueOf(ppn).Elem().CanAddr():", reflect.ValueOf(ppn).Elem().CanAddr())

}

 

reflect.ValueOf(n).CanSet(): false
reflect.ValueOf(pn).CanSet(): false
reflect.ValueOf(pn2).CanSet(): false
reflect.ValueOf(ppn).CanSet(): false
reflect.ValueOf(pn).Elem().CanSet(): true
reflect.ValueOf(pn2).Elem().CanSet(): false
reflect.ValueOf(ppn).Elem().CanSet(): true
reflect.ValueOf(n).CanAddr(): false
reflect.ValueOf(pn).CanAddr(): false
reflect.ValueOf(pn2).CanAddr(): false
reflect.ValueOf(ppn).CanAddr(): false
reflect.ValueOf(pn).Elem().CanAddr(): true
reflect.ValueOf(pn2).Elem().CanAddr(): false
reflect.ValueOf(ppn).Elem().CanAddr(): true

 

什么是可设置( CanSet )

首先需要先明确下,可设置是针对 reflect.Value 的。普通的变量要转变成为 reflect.Value 需要先使用 reflect.ValueOf () 来进行转化。

元素本身是不能设置,

元素的指针是肯定不能设置的,因为它是指针。

元素的指针指向的元素是空的时候也不能设置

元素的指针指向的元素(Elem)是可以设置的

 

什么是可地址( CanAddr )

 

在 reflect 包里面可以看到,除了 CanSet 之外,还有一个 CanAddr 方法。它们两个有什么区别呢?

CanAddr 方法和 CanSet 方法不一样的地方在于:对于一些结构体内的私有字段,我们可以获取它的地址,但是不能设置它。

package main

import (
"fmt"
"reflect"
)

type FooStruct struct {
A string
b int
}


func main() {
{
// struct
a := FooStruct{}
val := reflect.ValueOf(&a)
fmt.Println(val.Elem().FieldByName("b").CanSet()) // false
fmt.Println(val.Elem().FieldByName("b").CanAddr()) // true
}
}

 

 

CanAddr 方法和 CanSet 方法不一样的地方在于:对于一些结构体内的私有字段,我们可以获取它的地址,但是不能设置它。
所以,CanAddr 是 CanSet 的必要不充分条件:一个 Value 如果 CanAddr, 不一定 CanSet。但是一个变量如果 CanSet,它一定 CanAddr。

posted @ 2022-12-05 15:31  若-飞  阅读(225)  评论(0)    收藏  举报