【问题标题】:Cast an interface using a pointer of a Slice to iterate its values使用 Slice 的指针转换接口以迭代其值
【发布时间】:2021-08-01 04:42:31
【问题描述】:

上下文:

在 Echo 框架中使用自定义的 Binder 和 Validator。 binder 使用(interface{}, echo.Context) 的签名,但指针始终由echo.DefaultBinder 传递和检查。

当数组因某种未知原因被传递时,由于某种原因,我无法验证结构数组。因此,我正在尝试验证接口中的每个元素,如果此接口是数组或切片。

问题:

我找不到将interface 转换为value 而不是pointer 并遍历此数组的值以验证每个值的方法。

到目前为止我的代码:

func (cb *CustomBinder) Bind(i interface{}, c echo.Context) error {
    db := new(echo.DefaultBinder)
    validate := validator.New()
    if err := db.Bind(i, c); err != nil {
        return err
    }

    kind := reflect.ValueOf(i).Elem().Kind()
    if kind == reflect.Array || kind == reflect.Slice {
        
        // ... Iteration and Validation

    } else {
        if err := validate.Struct(i); err != nil {
            return err
        }
    }

    return nil
}

【问题讨论】:

    标签: validation go pointers echo reflect


    【解决方案1】:

    我宁愿使用类型断言而不是反射,因为反射在性能方面很慢并且使用起来不友好。
    为了说明我的意思,请查看此示例代码,其中我有一个函数,该函数接受 interface{} 类型的参数并根据数据类型打印值,

    package main
    
    import (
        "fmt"
    )
    
    func main() {
        var dynamicValue interface{}
    
        dynamicValue = []interface{}{"value1", "value2"}
        printValue(dynamicValue)
    
        dynamicValue = map[string]interface{}{"key1": "value1"}
        printValue(dynamicValue)
    
        dynamicValue = "value1"
        printValue(dynamicValue)
    
    }
    
    func printValue(i interface{}) {
        if arrayValue, isArray := i.([]interface{}); isArray {
            for index, value := range arrayValue {
                fmt.Printf("Index: %d Value: %v \n", index, value)
            }
        } else if mapValue, isMap := i.(map[string]interface{}); isMap {
            for key, value := range mapValue {
                fmt.Printf("Key: %s Value: %v \n", key, value)
            }
    
        } else if stringValue, isString := i.(string); isString {
            fmt.Println(stringValue)
        } else {
            fmt.Println("Invalid data type! Only supports string, arrays and maps ")
        }
    
    }
    
    

    输出:
    索引:0 值:value1
    索引:1 值:值2
    键:key1 值:value1
    价值1

    游乐场:https://play.golang.org/p/TMfojVdoi5b

    您可以在代码中使用这种类型断言逻辑来检查 interface 是否为切片并对其进行迭代以进行验证。
    像这样的,

    func (cb *CustomBinder) Bind(i interface{}, c echo.Context) error {
        db := new(echo.DefaultBinder)
        validate := validator.New()
        if err := db.Bind(i, c); err != nil {
            return err
        }
    
       
       if arrayValue, isArray := i.([]interface{}); isArray {
        // Iteration
        for index, value := range arrayValue {
            // Validation
        }
        } else {
            if err := validate.Struct(i); err != nil {
                return err
            }
        }
    
        return nil
    }
    

    【讨论】:

    • 我喜欢这个想法并且结构良好,不幸的是,代码无法识别自定义结构的指针,但确实可以通过将行 i.([]interface{}) 更改为 i.(*[]interface{}) 来识别数组。我可能必须等待自定义结构的泛型发布。
    猜你喜欢
    • 2012-09-06
    • 2011-05-22
    • 2010-10-19
    • 2023-04-04
    • 2020-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多