我们使用reflect.TypeOf 来读取接口变量的reflect.Type
package main
import (
"fmt"
"reflect"
)
func main() {
var x float64 = 3.4
fmt.Println("type:", reflect.TypeOf(x))
}
运行结果
type: float64
我们可能会疑惑,为什么没看到接口?这段代码看起来只是把一个 float64 类型的变量 x 传递给 reflect.TypeOf 并没有传递接口。其实在 reflect.TypeOf 的函数签名里包含一个空接口:
func TypeOf(i interface{}) Type
返回对象的名称,如果是基本对象例如int就返回int,如果是自定的如type intt int,返回的是intt
返回对象的静态类型,自定的type intt int,也是返回int
如果对象是个结构体,可以使用该函数返回对应下标的结构体字段的信息
StructField 的结构如下:
type StructField struct {
Name string // 字段名
PkgPath string // 字段路径
Type Type // 字段反射类型对象
Tag StructTag // 字段的结构体标签
Offset uintptr // 字段在结构体中的相对偏移
Index []int // Type.FieldByIndex中的返回的索引值
Anonymous bool // 是否为匿名字段
}
返回结构体成员字段数量
和上一条函数结合起来可以获取结构体内各成员的信息
package main
import (
"fmt"
"reflect"
)
func main() {
// 声明一个空结构体
type cat struct {
Name string
// 带有结构体tag的字段
Type int `json:"type" id:"100"`
}
// 创建cat的实例
ins := cat{Name: "mimi", Type: 1}
// 获取结构体实例的反射类型对象
typeOfCat := reflect.TypeOf(ins)
// 遍历结构体所有成员
for i := 0; i < typeOfCat.NumField(); i++ {
// 获取每个成员的结构体字段类型
fieldType := typeOfCat.Field(i)
// 输出成员名和tag
fmt.Printf("name: %v tag: '%v'\n", fieldType.Name, fieldType.Tag)
}
// 通过字段名, 找到字段类型信息
if catType, ok := typeOfCat.FieldByName("Type"); ok {
// 从tag中取出需要的tag
fmt.Println(catType.Tag.Get("json"), catType.Tag.Get("id"))
}
}
输出如下
name: Name tag: ''
name: Type tag: 'json:"type" id:"100"'
type 100
Tag 在结构体字段后方书写的格式如下:
`key1:"value1" key2:"value2"`
从其中提取信息的方法有
func (tag StructTag) Get(key string) string
//根据 Tag 中的键获取对应的值,例如`key1:"value1"`的 Tag 中,可以传入“key1”获得“value1”。
func (tag StructTag) Lookup(key string) (value string, ok bool)
//根据 Tag 中的键,查询值是否存在。
我们使用reflect.ValueOf 来读取接口变量的reflect.Value
用来返回该对象的反射中的reflect.Type类型,也就是上面的东西
将值 x 追加到切片 s 并返回生成的切片(返回的不是Value么??)
将切片 t 追加到切片 s 并返回生成的切片
返回结构体对象第i个字段的value
返回具有给定名称的结构字段。如果未找到任何字段,则返回零值。
以 float64 的形式返回 v 的基础值
索引返回 v 的第 i 个元素。如果 v 的 Kind 不是 Array、Slice 或 String 或 i 超出范围,则报错
将x(Value类型) 赋给值 v。如果 CanSet 返回 false,则报错
SetInt则是将int类型赋给v,SetString同理
下面这段代码虽然不能正常工作,但是非常值得研究:
var x float64 = 3.4
v := reflect.ValueOf(x)
v.SetFloat(7.1) // Error: will panic
这里问题不在于值7.1 不能被寻址,而是因为变量 v 是“不可写的”,“可写性”是反射类型变量的一个属性,但不是所有的反射类型变量都拥有这个属性。
package main
import (
"fmt"
"reflect"
)
func main() {
var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println("settability of v:", v.CanSet())
}
运行结果如下
settability of v: false
要想使其可写则
package main
import (
"fmt"
"reflect"
)
func main() {
var x float64 = 3.4
p := reflect.ValueOf(&x) // Note: take the address of x.
v := p.Elem()
fmt.Println("settability of p:", v.CanSet())
}
运行结果如下
settability of v: true
这里变量v就代表了变量x,所以我们可以对其进行修改
package main
import (
"fmt"
"reflect"
)
func main() {
var x float64 = 3.4
p := reflect.ValueOf(&x) // Note: take the address of x.
v := p.Elem()
v.SetFloat(7.1)
fmt.Println(v.Interface())
fmt.Println(x)
}
运行结果如下
7.1
7.1
将v的实际值作为一个空interface返回