Go语言的反射reflect使用大全
作者:努力的悟空
前言
Go语言作为一个高性能的静态语言,我们在写函数的时候,由于go语言的特性,我们需要定义变量类型,大多情况下,变量类型是固定结构体,这就会导致我们想做一个适配性较高的函数的时候,则需要将变量以及返回值用interface{}接口实现
一、映射的基本用法
1.获取类型信息
使用`reflect.TypeOf()`可以获取任何值的类型信息
var x float64 = 3.4 fmt.Println("type:", reflect.TypeOf(x))
2.获取值
使用`reflect.ValueOf()`可以获取reflect.Value类型表示的实际值:
var x float64 = 3.4 v := reflect.ValueOf(x) fmt.Println("value:", v) fmt.Println("type:", v.Type()) fmt.Println("kind:", v.Kind())
3.读取和设置值
通过reflect可以对变量的值进行读取和设置:
var x float64 = 3.4 p := reflect.ValueOf(&x) // 注意这里必须要传递x的地址 v := p.Elem() v.SetFloat(7.1)
4.使用Kind来区分类型
`reflect.Kind`可以用来区分基本类型:
v := reflect.ValueOf(x) if v.Kind() == reflect.Float64 { // x是float64类型 }
5.操作结构体
可以通过`reflect`包来动态地读取和设置结构体的字段,甚至可以调用方法:
type MyStruct struct { Field1 int Field2 string } s := MyStruct{Field1: 10, Field2: "Hello"} v := reflect.ValueOf(s) typeOfS := v.Type() for i := 0; i < v.NumField(); i++ { field := v.Field(i) fmt.Printf("%d: %s %s = %v ", i, typeOfS.Field(i).Name, field.Type(), field.Interface()) }
6.创建新实例
type MyStruct struct { Field1 int } var msType reflect.Type = reflect.TypeOf(MyStruct{}) msValue := reflect.New(msType).Elem() msValue.Field(0).SetInt(10)
7.调用方法
//动态调用方法 v := reflect.ValueOf(s) m := v.MethodByName("MethodName") args := []reflect.Value{reflect.ValueOf(arg1), reflect.ValueOf(arg2)} result := m.Call(args)
8.调用方法
对于映射、切片和数组类型,`reflect`包提供了额外的函数来动态操作它们;例如可以通过`reflect.Append`、`reflect.MakeSlice`等创建和操作切片:
a := []int{1,2,3} v := reflect.ValueOf(a) newValue := reflect.Append(v, reflect.ValueOf(4)) fmt.Println(newValue.Interface()) // [1 2 3 4]
二、使用实例
在GIN+GROM框架中我建立了一个表模板
type TempGeo struct { BSM string `gorm:"type:varchar(255);primary_key"` TBMJ float64 MAC string `gorm:"type:varchar(255)"` Name string `gorm:"type:varchar(255)"` Date string `gorm:"type:varchar(255)"` Geom string `gorm:"type:geometry(MultiPolygon,4326)"` }
我写了一个接口,想将这个表转换为Geojson
func (uc *UserController) ShowTempGeo(c *gin.Context) { bsm := c.Query("bsm") var mytable []models.TempGeo DB := models.DB DB.Where("bsm = ?", bsm).Find(&mytable) data := methods.MakeGeoJSON(mytable) c.JSON(http.StatusOK, data) }
其中的MakeGeoJSON函数就是使用了映射实现的,如果不使用映射,就会出现如果我重新造一个表,那么我就需要重写一个MakeGeoJSON函数并新定义变量,这是静态语言很麻烦的一个事情,还好go在这方面有一个映射的口子,让我们能写出泛用性函数。以下代码就是将数据都通过映射实现。
func MakeGeoJSON(items interface{}) interface{} { var FeaturesList []*geojson.Feature FeaturesList = []*geojson.Feature{} var sliceValue reflect.Value if reflect.TypeOf(items).Kind() == reflect.Slice { sliceValue = reflect.ValueOf(items) } else { sliceValue = reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(items)), 1, 1) sliceValue.Index(0).Set(reflect.ValueOf(items)) } for i := 0; i < sliceValue.Len(); i++ { t := sliceValue.Index(i).Interface() v := reflect.ValueOf(t) tt := reflect.TypeOf(t) geomField := v.FieldByName("Geom") if !geomField.IsValid() { continue } geomStr, _ := geomField.Interface().(string) properties := make(map[string]interface{}) for i := 0; i < v.NumField(); i++ { if tt.Field(i).Name != "Geom" { properties[strings.ToLower(tt.Field(i).Name)] = v.Field(i).Interface() } } wkbBytes, _ := hex.DecodeString(strings.Trim(geomStr, " ")) geom, _ := wkb.Unmarshal(wkbBytes) feature := geojson.NewFeature(geom) feature.Properties = properties FeaturesList = append(FeaturesList, feature) } features := geojson.NewFeatureCollection() features.Features = FeaturesList GeoJSON, _ := json.Marshal(features) var obj interface{} json.Unmarshal(GeoJSON, &obj) return obj }
总结
在Go语言中,`reflect`包被用来在运行时动态地操作对象。尽管这个包非常强大,但是它通常不建议用于日常编程,因为它会使代码更难理解和维护,同时也会减慢程序运行速度。但是当你需要编写通用代码或者框架,或者需要处理未知类型的数据时,`reflect` 包就显得非常有用。
到此这篇关于Go语言的反射reflect使用大全的文章就介绍到这了,更多相关Go语言 反射reflect内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!