Как преобразовать Reflect.Pointer() в [] строку при использовании pg.Array?

Я использую go-pg для написания пользовательской системы кэширования запросов, которая принимает аргументы запроса, которые передаются в функцию запроса, и генерирует хеш-ключ, который используется для Redis. Я использую Go, чтобы проверить типы аргументов, которые работают, пока я не использую pg.Array в качестве переданного аргумента.

Reflect дает мне Reflect.Ptr, но как извлечь структуру/массив указателя при вызове блока case case?

func GenerateQueryCacheKey(args ...interface{}) string {
    var argumentString = ""

    for _, arg := range args {

        v := reflect.ValueOf(arg)
        switch v.Kind() {
        case reflect.Array, reflect.Slice:
            ret := make([]interface{}, v.Len())

            for i := 0; i < v.Len(); i++ {
                ret[i] = v.Index(i).Interface()
            }

            GenerateQueryCacheKey(ret...)
        case reflect.Bool:
            argumentString += strconv.FormatBool(v.Bool())
        case reflect.String:
            argumentString += v.String()
        case reflect.Int:
            argumentString += string(v.Int())
        case reflect.Uint:
            argumentString += string(v.Uint())
        case reflect.Float32:
            argumentString += strconv.FormatFloat(v.Float(), 'E', -1, 32)
        case reflect.Invalid:
            log.Printf("Invalid type handle! " + fmt.Sprintf("%T", arg))
            argumentString += "nil"
        case reflect.Ptr:
            p := v.Elem()

            ret := make([]interface{}, p.Len())

            for i := 0; i < p.Len(); i++ {
                ret[i] = p.Index(i).Interface()
            }

            GenerateQueryCacheKey(ret...)
        default:
            log.Printf("Unhandled reflect type supplied! " + fmt.Sprintf("%T %T", arg, v))
            argumentString += "nil"
        }
    }

    h := md5.New()
    io.WriteString(h, argumentString)

    return fmt.Sprintf("%x", h.Sum(nil))
}

Определение pg.Array: https://sourcegraph.com/github.com/lib/pq/-/blob/array.go#L29:6

Обновлено: опубликованная ссылка имеет неправильное определение pg.Array. Я случайно взял не ту библиотеку с сайта sourcegraph.com.

"как извлечь структуру/массив указателя" Вы уже делаете p := v.Elem(), чтобы получить значение, на которое указывает указатель. У вас это не работает?
mkopriva 02.05.2019 21:27
«Как преобразовать Reflect.Pointer() в [] строку при использовании pg.Array?» Вы можете проверить, можно ли преобразовать Reflect.Type в другой. то есть v.Elem().Type().ConvertibleTo(reflect.TypeOf([]string{})). Если вы получаете true, вы можете использовать golang.org/pkg/reflect/#Value.Convert
mkopriva 02.05.2019 21:30

... или сверьтесь непосредственно с типом pgStringArray. v.Elem().Type() == reflect.TypeOf(pg.StringArray{}), а затем используйте golang.org/pkg/reflect/#Value.Convert

mkopriva 02.05.2019 21:32

Большую часть кода можно заменить на fmt.Sprint(arg). Возвращаемое значение вызовов GenerateQueryCacheKey игнорируется и поэтому не включается в хэш. Выражение string(v.Int()) делает не то, что вы думаете

Bayta Darell 03.05.2019 04:01

Я столкнулся с большим количеством проблем, используя отражение, и попробовал другой подход. Не уверен, что это лучший метод, но он работает.

Ajm113 03.05.2019 19:45
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
0
5
179
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Решено путем отказа от отражения и использования более прямого подхода.

Я просто импортировал типы.Array из pg и создал срез интерфейса {}, вручную добавил строки в срез интерфейса {} и использовал оператор распространения для создания рекурсивной функции на данный момент. Не уверен, что это лучший метод, но на данный момент он работает для меня.

func GenerateQueryCacheKey(args ...interface{}) string {
    var argumentString = ""

    for _, arg := range args {

        switch v := arg.(type) {
        case bool:
            argumentString += strconv.FormatBool(v)
        case string:
            argumentString += v
        case int:
            argumentString += strconv.Itoa(v)
        case uint64:
            argumentString += string(v)
        case float64:
            argumentString += strconv.FormatFloat(v, 'E', -1, 32)
        case *types.Array:
            stringArrayArgs := make([]interface{}, len(v.Value().([]string)))
            for i, vs := range v.Value().([]string) {
                stringArrayArgs[i] = vs
            }

            argumentString += GenerateQueryCacheKey(stringArrayArgs...)
        case nil:
        default:
            log.Printf("%T was requested and not handled!\n", v)
            argumentString += "nil"
        }
    }

    h := md5.New()
    io.WriteString(h, argumentString)

    return fmt.Sprintf("%x", h.Sum(nil))
}

Другие вопросы по теме