Golang如何对未知接口进行类型断言?

11

我明白可以通过反射获取对象的值,然后使用类型断言来获取实际对象:

obj := new(User)
out := reflect.ValueOf(obj).Elem().Interface().(User)
fmt.Println(out == *obj) // true

但是如果我不知道对象的类型是 User,我该如何进行类型断言?假设它在一个函数内,类似于:

func Foo(obj interface{}) bool {
    // out := reflect.ValueOf(obj).Elem().Interface().( ... )
    return out == *obj
}

func main() {
    obj := new(User)
    fmt.Println(Foo(obj))
}

Foo 函数中,你永远不会知道实际传递的对象类型是什么,那么如何完成类型断言?

1个回答

13
你不能这样做。类型断言允许你利用语言提供的静态类型检查,即使你有一个接口,它的类型没有被静态检查。它基本上是这样工作的:
你有一些静态类型变量 s,它的类型是 t。编译器通过拒绝编译如果你试图使用 s 作为不同类型来保证 s 总是具有类型 t。
你还有一些接口变量 i。i 的类型在编译时是未知的,所以编译器无法保证将 i 赋值给 s 不会破坏 s 具有类型 t 的保证。但是,你可以进行类型断言。类型断言通过说,“好吧,我会在运行时检查,只有当类型匹配时才会进行赋值。”来回避这个问题。编译器可以接受这个,因为它知道只有在类型匹配的情况下才会进行赋值,这意味着它仍然可以保证 s 具有类型 t。所以基本上在运行时发生的是:
if (i has type t) {
    s = i
} else {
    s = t{} // Zero value of t
}

你所要求的东西不可能实现的原因是编译器必须知道你要检查的类型,这样它才能写出我上面给出的伪代码。如果不知道t是什么,就无法知道s的静态类型应该是什么,也无法检查它是否正确。

谢谢,那很有道理。但是怎么样才能从传递的对象类型创建一个具体实例呢?当然,通过反射获取它并不会被视为引用。 - Marconi
2
你能做的最好的事情就是获取这种类型的接口值。类似这样:reflect.New(reflect.TypeOf(obj)).Interface() - joshlf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接