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

时间:2017-07-18 12:24:52

标签: go

我正在尝试创建一个函数,让我可以通过名称动态设置任意结构的值。例如。给定Page嵌入式Link结构,我希望能够将page.Link.Url设置为新字符串。

这是我的代码以及失败的测试:

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)
                }
            }
        }
    }
}

它成功设置了page.Title的值,但它没有尝试在嵌入式结构上设置值。我认为问题在于我最初调用函数传递对page的引用,但是当我递归调用setFieldSubFieldByName时,它传递的是实际对象,而不是指向它的指针。

有没有办法在递归之前获得对嵌入式结构的引用,或者是否有一些检查我可以在函数的开头执行以查明我是在查看实际实例还是只是指针?

我该如何解决这个问题?

0 个答案:

没有答案