当前位置: 代码网 > it编程>前端脚本>Golang > Go语言的反射reflect使用大全

Go语言的反射reflect使用大全

2024年09月08日 Golang 我要评论
前言go语言作为一个高性能的静态语言,我们在写函数的时候,由于go语言的特性,我们需要定义变量类型,大多情况下,变量类型是固定结构体,这就会导致我们想做一个适配性较高的函数的时候,则需要将变量以及返回

前言

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内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com