Рекурсивно расширяющееся определение структуры, содержащее указатели - PullRequest
0 голосов
/ 08 октября 2018

Этот вопрос основан на следующем: глубоко отразиться на структуре Мне нужно то же самое - расширить определение структуры, чтобы затем передать его как объект JSON, но с той лишь разницей, что структура содержит указатели на другие структуры.Таким образом, предоставленный код не может справиться с этим.Я попытался изменить его следующим образом:

func printFields(prefix string, t reflect.Type) {
    for i := 0; i < t.NumField(); i++ {
        f := t.Field(i)
        fmt.Printf("%v%v %v\n", prefix, f.Name, f.Type)
        if f.Type.Kind() == reflect.Struct {
            fmt.Println(reflect.New(f.Type))
            printFields(fmt.Sprintf("  %v", prefix), f.Type)
        } else if f.Type.Kind() == reflect.Ptr {
            fmt.Println("type ", f.Type )
            printFields(fmt.Sprintf("  %v", prefix), f.Type)
        }
    }
}

Но в случае указателей это приводит к панике.Как это исправить?

РЕДАКТИРОВАТЬ: получил то, что мне нужно:

func printFields(prefix string, t reflect.Type) {
    if t.Kind() != reflect.Struct {
        return
    }
    for i := 0; i < t.NumField(); i++ {
        f := t.Field(i)
        fmt.Printf("%v%v %v\n", prefix, f.Name, f.Type)
        if f.Type.Kind() == reflect.Struct {
            fmt.Println(reflect.New(f.Type))
            printFields(fmt.Sprintf("  %v", prefix), f.Type)
        } else if f.Type.Kind() == reflect.Ptr {
            printFields(fmt.Sprintf("  %v", prefix), f.Type.Elem())
        }
    }
}

func printExpandedStruct(s interface{}) {
    printFields("", reflect.ValueOf(s).Type())
}

1 Ответ

0 голосов
/ 08 октября 2018

Если тип поля является указателем, используйте тип элемента указателя.В остальном логика та же, что и в связанном вопросе.

func printFields(prefix string, t reflect.Type) {
    for i := 0; i < t.NumField(); i++ {
        f := t.Field(i)
        fmt.Printf("%v%v %v\n", prefix, f.Name, f.Type)
        ft := f.Type
        if ft.Kind() == reflect.Ptr {
            ft = ft.Elem()
        }
        if ft.Kind() == reflect.Struct {
            printFields(fmt.Sprintf("  %v", prefix), ft)
        }
    }
}

Запустите его на игровой площадке .

Следующий код обрабатывает более общий случай, когдаполя могут быть массивами, фрагментами, каналами, указателями или комбинациями этих типов.

func printFields(prefix string, t reflect.Type) {
    for i := 0; i < t.NumField(); i++ {
        f := t.Field(i)
        fmt.Printf("%v%v %v\n", prefix, f.Name, f.Type)
        ft := f.Type
        for ft.Kind() == reflect.Ptr ||
            ft.Kind() == reflect.Slice ||
            ft.Kind() == reflect.Array ||
            ft.Kind() == reflect.Chan {
            ft = ft.Elem()
        }
        if ft.Kind() == reflect.Struct {
            printFields(fmt.Sprintf("  %v", prefix), ft)
        }
    }
}

Запустить его на детской площадке .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...