Go语言的映射reflect使用大全

目录

前言

一、映射的基本用法

1.获取类型信息

2.获取值

3.读取和设置值

4.使用Kind来区分类型

5.操作结构体

6.创建新实例

7.调用方法

8.调用方法

二、使用实例

总结

前言

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`  包就显得非常有用。

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

努力的悟空

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值