dongnu4254 2019-05-02 19:17 采纳率: 100%
浏览 56
已采纳

使用pg.Array时如何将reflect.Pointer()转换为[]字符串?

I'm using go-pg to write a custom query cache system that takes a query arguments that are passed to Query function and generates a hash key that is used for Redis. I'm using Go's reflect to check the argument types which works, until I use pg.Array as a passed argument.

Reflect gives me reflect.Ptr, but how do I extract the pointer's struct/Array when the switch case block is called?

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 definition: https://sourcegraph.com/github.com/lib/pq/-/blob/array.go#L29:6

EDIT: The link posted has the incorrect definition of pg.Array. I accidentally grabbed the wrong library from sourcegraph.com.

  • 写回答

1条回答 默认 最新

  • dongweng6241 2019-05-03 17:45
    关注

    Solved by reverting away from reflect and using the more direct approach.

    I simply imported the types.Array from pg and created an interface{} slice and manually added the strings into the interface{} slice and used the spread operator to create a recursive function for the time being. Not sure if it's the best method, but it works for me at the moment.

    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!
    ", v)
                argumentString += "nil"
            }
        }
    
        h := md5.New()
        io.WriteString(h, argumentString)
    
        return fmt.Sprintf("%x", h.Sum(nil))
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?