Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reflection Go中的泛型编程。避免硬编码类型断言_Reflection_Go_Generic Programming - Fatal编程技术网

Reflection Go中的泛型编程。避免硬编码类型断言

Reflection Go中的泛型编程。避免硬编码类型断言,reflection,go,generic-programming,Reflection,Go,Generic Programming,我正在编写一个通用缓存机制,我需要在结构中设置一些属性,只知道它们的reflect.Type、属性名称和reflect.Value要在属性中设置,但我无法避免类型断言,这使得我的代码不是通用的 func main() { addressNew := Address{"New Address description!"} // In the real problem, i know the reflect.Type of value, but // the struct

我正在编写一个通用缓存机制,我需要在结构中设置一些属性,只知道它们的reflect.Type、属性名称和reflect.Value要在属性中设置,但我无法避免类型断言,这使得我的代码不是通用的

func main() {
    addressNew := Address{"New Address description!"}

    // In the real problem, i know the reflect.Type of value, but
    // the struct came to me as a interface{}, just like this method
    // Return many kinds of values from redis as interface{}, 
    // (Customer, Order, Address, Product, SKU etc), in a generic way,
    // but returns the reflect.Type of value also.
    interfaceSomeValue := getMyValue()

    fmt.Printf("%v", interfaceSomeValue)
    fmt.Println("")

    // This portion of code comes from my cache mechanism, that is a library 
    // used by other projects. My cache lib really can't know all others
    // type structs to perform the type assertion, but the cache mechanism know 
    // the reflect.Type of the interface. 
    // If you try at this way, will cause a panic by try to access a FieldByName
    // in a interface, because the Customer comes from getMyValue and 
    // becomes a interface{}, and now a type assertion is 
    // required -> http://play.golang.org/p/YA8U9_KzC9
    newCustomerNewAttribute := SetAttribute(&interfaceSomeValue, "Local", interface{}(addressNew), reflect.TypeOf(Customer{}))

    fmt.Printf("%v", newCustomerNewAttribute)
    fmt.Println("")
}

func SetAttribute(object interface{}, attributeName string, attValue interface{}, objectType reflect.Type) interface{} {
    if reflect.ValueOf(object).Kind() != reflect.Ptr {
        panic("need a pointer")
    }

    value := reflect.ValueOf(object).Elem()
    field := value.FieldByName(attributeName)
    valueForAtt := reflect.ValueOf(attValue)
    field.Set(valueForAtt)
    return value.Interface()
}


我终于找到了一种方法。请按照下面的“围棋场”和代码片段进行操作:


你能提供一个小的例子来说明你要解决的问题吗?类型断言对于尝试泛型编程的go程序来说是正常的。谢谢你的回答,Karmastan。实际上我在围棋场上举了个例子。我从缓存存储(Redis)中获取要放入属性中的值,但是从存储中获取该值的函数返回一个接口和关于该值的reflect.Type。请注意,我的系统中可能有数百种类型的结构,这破坏了我的通用代码。。。谢谢你的帮助。请准确地展示你正在努力实现的目标。这与你的上一个问题相同,但还有一层间接的意思。您没有解释为什么需要类型断言,以及为什么不能只使用反射。

//new approach SetAttribute, without any hard coded type assertion, just based on objectType parameter
func SetAttribute(myUnknownTypeValue *interface{}, attributeName string, attValue interface{}, objectType reflect.Type) {

    // create value for old val
    oldValue := reflect.ValueOf(*myUnknownTypeValue)

    //create a new value, based on type
    newValue := reflect.New(objectType).Elem()
    // set the old value to the new one, making the 
    // implicit type assertion, not hard coding that.
    newValue.Set(oldValue)

    //set value attribute to the new struct, copy of the old one
    field := newValue.FieldByName(attributeName)
    valueForAtt := reflect.ValueOf(attValue)
    field.Set(valueForAtt)

    //capture the new value from reflect.Value
    newValInterface := newValue.Interface()
    //set the new value to the pointer
    *myUnknownTypeValue = newValInterface
}