通过包含完整路径的给定字符串访问结构字段

huangapple go评论78阅读模式
英文:

Accessing struct field by a given string that contains the full path

问题

如果你想使用字符串来访问结构体中指定的字段,你可以使用反射(Reflect)包来实现。首先,你需要使用reflect.ValueOf()函数获取结构体的反射值。然后,你可以使用FieldByName()方法来获取指定字段的反射值。下面是一个示例代码:

package main

import (
	"fmt"
	"reflect"
)

type Stream struct {
	Fields []Field
}

type Field struct {
	Name string
}

func main() {
	stream := Stream{
		Fields: []Field{
			{Name: "Field 1"},
			{Name: "Field 2"},
		},
	}

	fieldName := "Stream.Fields[0].Name"

	// 获取结构体的反射值
	streamValue := reflect.ValueOf(stream)

	// 使用字符串访问指定字段的反射值
	fieldValue := getFieldByString(streamValue, fieldName)

	// 输出字段的值
	fmt.Println(fieldValue.Interface())
}

func getFieldByString(v reflect.Value, fieldName string) reflect.Value {
	// 按照点号分割字段名
	fieldNames := strings.Split(fieldName, ".")

	// 逐级获取字段的反射值
	for _, name := range fieldNames {
		if v.Kind() == reflect.Ptr {
			v = v.Elem()
		}
		v = v.FieldByName(name)
	}

	return v
}

在上面的示例中,我们定义了一个Stream结构体和一个Field结构体。然后,我们创建了一个Stream实例,并给fieldName赋值为"Stream.Fields[0].Name"。通过调用getFieldByString()函数,我们可以获取到指定字段的反射值,并将其输出到控制台上。

请注意,这只是一个简单的示例,实际使用中可能需要根据具体情况进行适当的修改。希望对你有帮助!

英文:

A validator package gives me back strings like this if a given field in my struct doesn't pass the validation:

myString := "Stream.Fields[0].Name"

How can i use this string to gain access to the struct field specified in it? I need to reference it somehow but i have no idea where to start with.

I'm beginning to learn Go and already came across the "Reflect" package which seems to be able to do that but i don't know what to look for or how to formulate the right question.

答案1

得分: 6

你需要使用reflect包来实现这个功能。下面是一个示例函数,给定一个实例和字符串键(例如Stream.Details.Name),它将返回实例StreamDetails字段的Name值。

这个函数适用于没有arraymap操作符的结构体,只有.操作符。你可以扩展它以支持[]操作符。

func getValueFromStruct(keyWithDots string, object interface{}) (interface{}, error) {
    keySlice := strings.Split(keyWithDots, ".")
    v := reflect.ValueOf(object)
    // 遍历字段名,忽略第一个字段名,因为它可能是当前实例的名称
    // 如果想支持像slice、map等类型的结构体,可以将其改为递归函数
    for _, key := range keySlice[1:] {
        for v.Kind() == reflect.Ptr {
            v = v.Elem()
        }
        // 只接受结构体类型
        if v.Kind() != reflect.Struct {
            return nil, fmt.Errorf("只接受结构体类型;当前类型为 %T", v)
        }

        v = v.FieldByName(key)
    }
    return v, nil
}

这是一个Go Playground的链接:https://play.golang.org/p/NIRdGONZBhP

英文:

You need to use reflect package for this.
Here I have written a sample function which given an instance and string key like Stream.Details.Name will return the Name from the field Details of instance Stream

This works for structs without array or map operators , just the . operator . You may extend this to support the [] aswell

func getValueFromStruct(keyWithDots string, object interface{}) (interface{}, error) {
	keySlice := strings.Split(keyWithDots, ".")
	v := reflect.ValueOf(object)
	// iterate through field names ,ignore the first name as it might be the current instance name
	// you can make it recursive also if want to support types like slice,map etc along with struct
	for _, key := range keySlice[1:] {
		for v.Kind() == reflect.Ptr {
			v = v.Elem()
		}
		// we only accept structs
		if v.Kind() != reflect.Struct {
			return nil, fmt.Errorf("only accepts structs; got %T", v)
		}

		v = v.FieldByName(key)
	}
	return v, nil
}

Here is golang play link : https://play.golang.org/p/NIRdGONZBhP

答案2

得分: 0

这个库也存在,可能可以满足你的需求:
https://github.com/mcuadros/go-lookup

该库在底层使用了reflect包

英文:

This library also exists, which might do what you want:
https://github.com/mcuadros/go-lookup

The lib uses the reflect package under the hood.

huangapple
  • 本文由 发表于 2017年1月3日 20:56:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/41444049.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定