dongmu5815 2017-07-18 12:24
浏览 50

如何判断变量是接口还是指向一个接口的指针

I'm trying to create a function that will let me set values on arbitrary structs dynamically by name. E.g. given a Page with an embedded Link struct, I want to be able to set page.Link.Url to a new string.

Here's my code along with a failing test:

func TestSetFieldSubFieldByName(t *testing.T) {
    page := APage {
        "page title",
        ALink {
            "link title",
            "http://www.example.com",
        },
    }

    newPageTitle := "New page title"

    setFieldSubFieldByName(&page, "Title", newPageTitle)

    if page.Title != newPageTitle {
        t.Errorf("Expected %s != %s", newPageTitle, page.Title)
    }

    newUrl := "http://new.example.com"

    setFieldSubFieldByName(&page, "Link.Url", newUrl)

    if page.Link.Url != newUrl {
        t.Errorf("Expected %s != %s", newUrl, page.Link.Url)
    }
}

type ALink struct {
    Title string
    Url string
}


type APage struct {
    Title string
    Link ALink
}

// Sets the value of a struct's field by name
func setFieldSubFieldByName(object interface{}, inputFieldName string, newValue string) {
    log.Printf("Will try to set field '%s' to '%s' on %#v (type %T)", inputFieldName, newValue, object, object)

    reflectedValues := reflect.ValueOf(object)

    fieldNameParts := strings.Split(inputFieldName, ".")
    fieldName := fieldNameParts[0]

    // struct
    reflectedElem := reflectedValues.Elem()

    if reflectedElem.Kind() == reflect.Struct {

        // exported field
        field := reflectedElem.FieldByName(fieldName)
        log.Printf("fieldByName returned %#v for field '%s'", field, fieldName)

        if field.IsValid() {
            // A Value can be changed only if it is addressable and was not obtained by the use of unexported struct fields.
            if field.CanSet() {
                // change value of N
                if field.Kind() == reflect.String {
                    field.SetString(newValue)
                    log.Printf("Field '%s' successfully updated to '%s'", fieldName, newValue)
                } else if field.Kind() == reflect.Struct && len(fieldNameParts) > 0 {
                    log.Printf("Trying to set subfield '%s' to '%s'", fieldNameParts[1], newValue)
                    subObj := field.Interface()
                    setFieldSubFieldByName(subObj, fieldNameParts[1], newValue)
                }
            }
        }
    }
}

It successfully sets the value of page.Title, but it's failing trying to set a value on the embedded struct. I think the issue is that I initially invoke the function passing a reference to page, but when I recursively call setFieldSubFieldByName it passes the actual object, not a pointer to it.

Is there a way of either getting a reference to the embedded struct before recursing, or is there some check I can perform at the start of the function to find out whether I'm looking at the actual instance or just a pointer?

How can I fix this?

  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥15 素材场景中光线烘焙后灯光失效
    • ¥15 请教一下各位,为什么我这个没有实现模拟点击
    • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
    • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
    • ¥20 有关区间dp的问题求解
    • ¥15 多电路系统共用电源的串扰问题
    • ¥15 slam rangenet++配置
    • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
    • ¥15 ubuntu子系统密码忘记
    • ¥15 保护模式-系统加载-段寄存器