猿问

如何使用运行时定义的类型更新函数中接口的值?

假设我有一个结构用户


type User struct {

    Name     string `owm:"newNameFromAPI"`

}

下面的代码初始化结构并将其传递给函数


func main() {   

    dest := User{

        Name: "Sebastien",

    }

    

    deepUpdate(dest, "owm")

}

该函数使用反射来迭代结构的所有字段并相应地更新它们(为清楚起见,删除了几个代码块)


func deepUpdate(destinationInterface interface{}, selector string) {


    // Here I'm not supposed to know that the type is `User`

    // And if I just use dest := destinationInterface, the value won't update

    dest := destinationInterface.(User)


    // Pointer to struct - addressable

    destVal := reflect.ValueOf(&dest)

    destType := reflect.TypeOf(&dest)

    // psindirect := reflect.Indirect(destVal) // ? ValueOf(<Ptr Value>) Requires to be adressed via reflect.Indirect() to access Field - https://stackoverflow.com/a/50098755/9077800


    // Struct

    destValElem := destVal.Elem()

    destTypeElem := destType.Elem()


    // Iterate over all fields of the struct

    for i := 0; i < destValElem.NumField(); i++ {

        // // for i := 0; i < destTypeElem.NumField(); i++ {

        destValField := destValElem.Field(i)

        destTypeField := destTypeElem.Field(i)


        switch destValField.Kind() {

        // Field is a struct

        case reflect.Struct:

            // Recursion

            fmt.Println("IS A STRUCT")

        default:

            // Get the complete tag

            tag := destTypeField.Tag

            if len(tag) == 0 {

                continue

            }


            // Get the value of our custom tag key

            tagVal := tag.Get(selector)

            if len(tagVal) == 0 {

                continue

            }           

}

问题是以下行,因为我不应该知道要将 转换为 .destinationInterfaceUser


如何将接口动态转换为在运行时定义的某个未知类型,或者以任何其他方式获取更新的“John”而不是“Sebastien”的相同输出?Name


dest := destinationInterface.(User)

这是在戈朗游戏狗上运行的完整代码


https://play.golang.org/p/sYvz-Fwp97P


波斯汪
浏览 74回答 1
1回答

至尊宝的传说

您不必知道 .该示例不是递归的,但可以轻松升级。destpackage mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "reflect")type User struct {&nbsp; &nbsp; Name string `owm:"newNameFromAPI"`}func main() {&nbsp; &nbsp; dest := User{&nbsp; &nbsp; &nbsp; &nbsp; Name: "Sebastien",&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Println("Before:", dest.Name)&nbsp; &nbsp; deepUpdate(&dest, "owm")&nbsp; &nbsp; fmt.Println("After:", dest.Name)}func deepUpdate(dest interface{}, selector string) {&nbsp; &nbsp; //Get the reflect value of dest&nbsp; &nbsp; rv := reflect.ValueOf(dest)&nbsp; &nbsp; //Dereference every pointers&nbsp; &nbsp; for rv.Kind() == reflect.Ptr {&nbsp; &nbsp; &nbsp; &nbsp; rv = reflect.Indirect(rv)&nbsp; &nbsp; }&nbsp; &nbsp; //Check if its a struct, should use panic or return error&nbsp; &nbsp; if reflect.TypeOf(rv.Interface()).Kind() != reflect.Struct {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("NOT A STRUCT")&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; }&nbsp; &nbsp; //Loop over the fields&nbsp; &nbsp; for i := 0; i < rv.NumField(); i++ {&nbsp; &nbsp; &nbsp; &nbsp; //Get the tag value&nbsp; &nbsp; &nbsp; &nbsp; tag := rv.Type().Field(i).Tag.Get(selector)&nbsp; &nbsp; &nbsp; &nbsp; if tag == "" {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; //Get the source&nbsp; &nbsp; &nbsp; &nbsp; sourceValue := "John"&nbsp; &nbsp; &nbsp; &nbsp; //Assign the source to the dest's corresponding field&nbsp; &nbsp; &nbsp; &nbsp; if rv.Field(i).CanSet() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rv.Field(i).Set(reflect.ValueOf(sourceValue))&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}唯一的问题是,您必须使用与相应字段相同的类型。sourceValue工作示例:https://goplay.space/#D0CmTaS5AiP
随时随地看视频慕课网APP

相关分类

Go
我要回答