Is it possible to determine (using reflect
) whether an instance of an arbitrary type can be set to an arbitrary value, i.e. to determine whether Value.Set()
would panic due to type incompatibility?
An MCVE is set out below. What I want to know is effectively 'can I write set()
without using the defer/recover construct?'
I'd like to avoid defer
not only because it seems ugly, but because Value.Set()
may panic for other reasons.
Note this is not merely a question of comparing the types for equality, as the o2
example below shows.
package main
import (
"fmt"
"reflect"
)
// set a value V to interface i, returning true if this can be done, else false
//
// CAN WE WRITE THIS WITHOUT HAVING TO USE DEFER / RECOVER?
//
func set(v reflect.Value, i interface{}) bool {
success := true
defer func() {
if r := recover(); r != nil {
success = false
}
}()
v.Set(reflect.ValueOf(i))
return success
}
// get the type of a typed nil
func getType(typedNil interface{}) reflect.Type {
return reflect.TypeOf(typedNil).Elem()
}
func main() {
t1 := getType((*int)(nil))
o1 := reflect.New(t1)
t2 := getType((*interface{})(nil))
o2 := reflect.New(t2)
var ok bool
var aInt = 456
var aString string = "hello"
var aUint uint = 123
// Set o1 to various types
ok = set(o1.Elem(), aInt) // Should return true
fmt.Printf("After o1 set to aInt returned %v: obj is type %T content '%v'\n", ok, o1.Elem().Interface(), o1.Elem().Interface())
ok = set(o1.Elem(), aString) // Should return false
fmt.Printf("After o1 set to aString returned %v: obj is type %T content '%v'\n", ok, o1.Elem().Interface(), o1.Elem().Interface())
ok = set(o1.Elem(), aUint) // Should return false
fmt.Printf("After o1 set to aUint returned %v: obj is type %T content '%v'\n", ok, o1.Elem().Interface(), o1.Elem().Interface())
fmt.Println("")
// Set o2 to various types
ok = set(o2.Elem(), aInt) // Should return true
fmt.Printf("After o2 set to aInt returned %v: obj is type %T content '%v'\n", ok, o2.Elem().Interface(), o2.Elem().Interface())
ok = set(o2.Elem(), aString) // Should return true
fmt.Printf("After o2 set to aString returned %v: obj is type %T content '%v'\n", ok, o2.Elem().Interface(), o2.Elem().Interface())
ok = set(o2.Elem(), aUint) // Should return true
fmt.Printf("After o2 set to aUint returned %v: obj is type %T content '%v'\n", ok, o2.Elem().Interface(), o2.Elem().Interface())
}
Aucun commentaire:
Enregistrer un commentaire