最终,我找到了一种方法。请遵循下面的Go Playground和代码段:
前往游乐场:避免硬编码类型声明
//new approach SetAttribute, without any hard coded type assertion, just based on objectType parameterfunc 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}解决方法
我正在编程一个通用的缓存机制,我需要在结构中设置一些属性,这些结构只知道它们的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()}
前往Playground解决问题(通过硬编码类型断言工作)…
前往Playground解决问题(不适用于未知界面)