我不想深入了解下面情况的基本原理。它与解组一个序列化对象有关,该对象可以是任何一组固定类型,但你不知道哪种类型。
我有以下类型:
type I interface {
Do()
}
type someI struct {}
func (i *someI) Do() {}
type otherI struct {}
func (i *otherI) Do() {}
因此,两个结构指针实现接口I
。
现在我有这个方法想要返回类型I
的值:
func GetSomeI(marshalled []byte) (I, error) {
var obj interface{}
// The following method magically puts an instance
// of either someI or otherI into obj.
magicUnmarshall(marshalled, obj)
// The problem now is that we cannot return obj,
// because the raw structs don't implement I.
// One solution would be to do a type switch like this:
switch obj.(type) {
case someI:
i := obj.(someI)
return &i, nil
case otherI:
i := obj.(otherI)
return &i, nil
default:
return nil, errors.New("marschalled object was not of type I")
}
// But now consider the case that there are quite some
// different implementations of I.
// We would prefer to have a general way of getting
// a reference to obj.
}
答案 0 :(得分:3)
要判断interface{}
中包含的值是否实现了其他界面(I
),您只需使用type assertion。
请注意,您必须将要将结果解组的变量的地址传递给。
出于演示目的,让我们使用以下magicUnmarshal()
函数:
func magicUnmarshal(what int, obj interface{}) {
v := reflect.ValueOf(obj).Elem()
switch what {
case 0:
v.Set(reflect.ValueOf(&someI{}))
case 1:
v.Set(reflect.ValueOf(&otherI{}))
case 2:
v.Set(reflect.ValueOf("just a string"))
case 3:
v.Set(reflect.ValueOf(someI{}))
case 4:
v.Set(reflect.ValueOf(otherI{}))
}
}
请注意,case 3
和case 4
正在返回非指针。
您的GetSomeI()
实施可以是:
func GetSomeI(what int) (I, error) {
var obj interface{}
magicUnmarshal(what, &obj)
// Try the value as-is:
if i, ok := obj.(I); ok {
return i, nil
}
// No success. Try a pointer to the value:
v := reflect.Indirect(reflect.New(reflect.TypeOf(obj)))
v.Set(reflect.ValueOf(obj))
pobj := v.Addr().Interface()
if i, ok := pobj.(I); ok {
return i, nil
}
return nil, fmt.Errorf("%T does not implement I!", obj)
}
首先GeSomeI()
测试magicUnmarshal()
形式的值是否实现I
,如果是,则按原样使用。如果没有,我们构造一个新的使用反射,并获取其地址(指向值的指针),我们测试它。如果该指针实现I
,我们将返回它。
测试它:
func main() {
for what := 0; what < 5; what++ {
i, err := GetSomeI(what)
fmt.Printf("%T %v\n", i, err)
}
}
输出是(在Go Playground上尝试):
*main.someI <nil>
*main.otherI <nil>
<nil> string does not implement I!
*main.someI <nil>
*main.otherI <nil>