分享
  1. 首页
  2. 文章

golang如何获取变量的类型:反射,类型断言

伊布 · · 28836 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

感觉接口的理解还有些不是很清楚,强写一篇

如果某个函数的入参是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 *rtypeword 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:



有疑问加站长微信联系(非本文作者)

本文来自:ieevee.com

感谢作者:伊布

查看原文:golang如何获取变量的类型:反射,类型断言

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
28836 次点击 ∙ 1 赞
1 回复 | 直到 2018年07月05日 10:00:17
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏