感觉接口的理解还有些不是很清楚,强写一篇
如果某个函数的入参是interface{},有下面几种方式可以获取入参的方法:
1 fmt:
import"fmt"funcmain(){v:="hello world"fmt.Println(typeof(v))}functypeof(vinterface{})string{returnfmt.Sprintf("%T",v)}
2 反射:
import("reflect""fmt")funcmain(){v:="hello world"fmt.Println(typeof(v))}functypeof(vinterface{})string{returnreflect.TypeOf(v).String()}
3 类型断言:
funcmain(){v:="hello world"fmt.Println(typeof(v))}functypeof(vinterface{})string{switcht:=v.(type){caseint:return"int"casefloat64:return"float64"//... etcdefault:_=treturn"unknown"}}
其实前两个都是用了反射,fmt.Printf("%T")里最终调用的还是reflect.TypeOf()。
func(p*pp)printArg(arginterface{},verbrune){...// Special processing considerations.// %T (the value's type) and %p (its address) are special; we always do them first.switchverb{case'T':p.fmt.fmt_s(reflect.TypeOf(arg).String())returncase'p':p.fmtPointer(reflect.ValueOf(arg),'p')return}
reflect.TypeOf()的参数是v interface{},golang的反射是怎么做到的呢?
在golang中,interface也是一个结构体,记录了2个指针:
- 指针1,指向该变量的类型
- 指针2,指向该变量的value
如下,空接口的结构体就是上述2个指针,第一个指针的类型是type rtype struct;非空接口由于需要携带的信息更多(例如该接口实现了哪些方法),所以第一个指针的类型是itab,在itab中记录了该变量的动态类型: typ *rtype 。
// emptyInterface is the header for an interface{} value.typeemptyInterfacestruct{typ*rtypewordunsafe.Pointer}// nonEmptyInterface is the header for a interface value with methods.typenonEmptyInterfacestruct{// see ../runtime/iface.go:/Itabitab*struct{ityp*rtype// static interface typetyp*rtype// dynamic concrete typelinkunsafe.Pointerbadint32unusedint32fun[100000]unsafe.Pointer// method table}wordunsafe.Pointer}
我们来看看reflect.TypeOf():
// TypeOf returns the reflection Type that represents the dynamic type of i.// If i is a nil interface value, TypeOf returns nil.funcTypeOf(iinterface{})Type{eface:=*(*emptyInterface)(unsafe.Pointer(&i))returntoType(eface.typ)}
TypeOf看到的是空接口interface{},它将变量的地址转换为空接口,然后将将得到的rtype转为Type接口返回。需要注意,当调用reflect.TypeOf的之前,已经发生了一次隐式的类型转换,即将具体类型的向空接口转换。这个过程比较简单,只要拷贝typ *rtype和word unsafe.Pointer就可以了。
例如w := os.Stdout,该变量的接口值在内存里是这样的:
A *os.File interface value
那么对于第三种,类型断言是怎么判断是不是某个接口呢?回到最初,在golang中,接口是一个松耦合的概念,一个类型是不是实现了某个接口,就是看该类型是否实现了该接口要求的所有函数,所以,类型断言判断的方法就是检查该类型是否实现了接口要求的所有函数。
走读k8s代码的时候,可以看到比较多的类型断言的用法:
funcLeastRequestedPriorityMap(pod*api.Pod,metainterface{},nodeInfo*schedulercache.NodeInfo)(schedulerapi.HostPriority,error){varnonZeroRequest*schedulercache.ResourceifpriorityMeta,ok:=meta.(*priorityMetadata);ok{nonZeroRequest=priorityMeta.nonZeroRequest}else{// We couldn't parse metadata - fallback to computing it.nonZeroRequest=getNonZeroRequests(pod)}returncalculateUnusedPriority(pod,nonZeroRequest,nodeInfo)}
类型断言的实现在src/runtime/iface.go里(?),不过这块代码没看懂,等以后再更新吧。
funcassertI2I2(inter*interfacetype,iiface)(riface,bbool){tab:=i.tabiftab==nil{return}iftab.inter!=inter{tab=getitab(inter,tab._type,true)iftab==nil{return}}r.tab=tabr.data=i.datab=truereturn}funcassertE2I2(inter*interfacetype,eeface)(riface,bbool){t:=e._typeift==nil{return}tab:=getitab(inter,t,true)iftab==nil{return}r.tab=tabr.data=e.datab=truereturn}
Ref: