如果某个函数的入参是interface{},有下面几种方式可以获取入参的方法:

1 fmt:

import "fmt"
func main() {
v := "hello world"
fmt.Println(typeof(v))
}
func typeof(v interface{}) string {
return fmt.Sprintf("%T", v)
}

2 反射:

import (
"reflect"
"fmt"
)
func main() {
v := "hello world"
fmt.Println(typeof(v))
}
func typeof(v interface{}) string {
return reflect.TypeOf(v).String()
}

3 类型断言:

func main() {
v := "hello world"
fmt.Println(typeof(v))
}
func typeof(v interface{}) string {
switch t := v.(type) {
case int:
return "int"
case float64:
return "float64"
//... etc
default:
_ = t
return "unknown"
}
}

其实前两个都是用了反射,fmt.Printf(“%T”)里最终调用的还是reflect.TypeOf()

func (p *pp) printArg(arg interface{}, verb rune) {
...
// Special processing considerations.
// %T (the value's type) and %p (its address) are special; we always do them first.
switch verb {
case 'T':
p.fmt.fmt_s(reflect.TypeOf(arg).String())
return
case '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.
type emptyInterface struct {
typ *rtype
word unsafe.Pointer
} // nonEmptyInterface is the header for a interface value with methods.
type nonEmptyInterface struct {
// see ../runtime/iface.go:/Itab
itab *struct {
ityp *rtype // static interface type
typ *rtype // dynamic concrete type
link unsafe.Pointer
bad int32
unused int32
fun []unsafe.Pointer // method table
}
word unsafe.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.
func TypeOf(i interface{}) Type {
eface := *(*emptyInterface)(unsafe.Pointer(&i))
return toType(eface.typ)
}

TypeOf看到的是空接口interface{},它将变量的地址转换为空接口,然后将将得到的rtype转为Type接口返回。需要注意,当调用reflect.TypeOf的之前,已经发生了一次隐式的类型转换,即将具体类型的向空接口转换。这个过程比较简单,只要拷贝typ *rtypeword unsafe.Pointer就可以了。

例如w := os.Stdout,该变量的接口值在内存里是这样的:

那么对于第三种,类型断言是怎么判断是不是某个接口呢?回到最初,在golang中,接口是一个松耦合的概念,一个类型是不是实现了某个接口,就是看该类型是否实现了该接口要求的所有函数,所以,类型断言判断的方法就是检查该类型是否实现了接口要求的所有函数。

走读k8s代码的时候,可以看到比较多的类型断言的用法:

func LeastRequestedPriorityMap(pod *api.Pod, meta interface{}, nodeInfo *schedulercache.NodeInfo) (schedulerapi.HostPriority, error) {
var nonZeroRequest *schedulercache.Resource
if priorityMeta, ok := meta.(*priorityMetadata); ok {
nonZeroRequest = priorityMeta.nonZeroRequest
} else {
// We couldn't parse metadata - fallback to computing it.
nonZeroRequest = getNonZeroRequests(pod)
}
return calculateUnusedPriority(pod, nonZeroRequest, nodeInfo)
}

类型断言的实现在src/runtime/iface.go里(?),不过这块代码没看懂,等以后再更新吧。

func assertI2I2(inter *interfacetype, i iface) (r iface, b bool) {
tab := i.tab
if tab == nil {
return
}
if tab.inter != inter {
tab = getitab(inter, tab._type, true)
if tab == nil {
return
}
}
r.tab = tab
r.data = i.data
b = true
return
} func assertE2I2(inter *interfacetype, e eface) (r iface, b bool) {
t := e._type
if t == nil {
return
}
tab := getitab(inter, t, true)
if tab == nil {
return
}
r.tab = tab
r.data = e.data
b = true
return
}
 查看原文地址

golang获取变量数据类型的更多相关文章

  1. golang 获取变量类型的字符串格式 列举变量类型

    fmt.Println(reflect.TypeOf(var)) switch xxx.(type){ case int:.... case float32:... case float64:... ...

  2. Go-获取变量数据类型

    package main import ( "fmt" "reflect" //这个包里的TypeOf方法获取变量数据类型 ) func main(){ b : ...

  3. JS魔法堂:函数重载 之 获取变量的数据类型

    Brief 有时我们需要根据入参的数据类型来决定调用哪个函数实现,就是说所谓的函数重载(function overloading).因为JS没有内置函数重载的特性,正好给机会我们思考和实现一套这样的机 ...

  4. typeof获取变量的数据类型 javascript

    获取变量的数据类型:typeof <!DOCTYPE html> <html lang="en"> <head> <meta charse ...

  5. Java知识日常收集整理001Java获取变量的数据类型的实现方法

    一.具体情况区分 对于简单类型变量,是无法直接获得变量类型的:要想获取,必须自定义函数进行返回. 对于包装类型变量,是可以直接获得的,变量名称.getClass().getName(); 二.代码实现 ...

  6. golang之基本数据类型

    目录 一.golang之基本数据类型 1. 整型 (1)有符号(范围是负数.0和正数) (2)无符号(范围是0和正数) (3)特殊整型 (4)数字字面量语法 2. 浮点型 3. 复数类型 4. 布尔类 ...

  7. Golang的基础数据类型-浮点型

    Golang的基础数据类型-浮点型 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.浮点型概述 Go语言提供两种精度的浮点数,即float32和float64,其中float32 ...

  8. Golang的变量定义及使用案例

    Golang的变量定义及使用案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.变量的定义 package main import "fmt" func m ...

  9. Learn day1 变量/数据类型

    1.Python 简介 (1) 1989年开发的语言,创始人范罗苏姆(Guido van Rossum),别称:龟叔(Guido). (2) python具有非常多并且强大的第三方库,使得程序开发起来 ...

随机推荐

  1. Python一篇学会多进程

    阅读目录 1. Process 2. Lock 3. Semaphore 4. Event 5. Queue 6. Pipe 7. Pool 序. multiprocessing python 中的多 ...

  2. 性能测试—JMeter 常用元件(二)

    性能测试—JMeter 常用元件(二) <零成本web性能测试>第三章 Web性能测试脚本录制与开发中JMeter常用测试元件 测试计划描述了JMeter运行时将会执行的一系列步骤,一个完 ...

  3. Python处理json数据--世界国家维度数据

    1.准备国家的json数据 将准备好的json数据放在指定的目录下,此处可以重这里下载 2.测试编写python脚本处理json提取字段值 #coding:utf8 import time, re, ...

  4. WPF捕获全局未处理异常

    在WPF开发过程中我们一般都用try/catch块来捕获异常,但不是每个异常我们都能捕获,程序总会出现一些意想不到情况,抛出一些未捕获的异常,这时就要用到全局异常捕获,即在程序的最外层加上捕获未处理异 ...

  5. threejs的学习笔记

    很多时候,我们在开发3d效果的时候,容易搞不清楚x,y,z坐标分别指示哪个方向 在开发threejs的时候可以先把坐标系添加到场景中,起到一个启示作用. js // show axes in the ...

  6. fastdfs-client-java操作fastdfs

    一.在https://github.com/happyfish100/fastdfs-client-java 下载客户端,解压后并执行ant命令,在E:\tools\libs\fastdfs\fast ...

  7. 01背包--hdu2639

    hdu-2639 The title of this problem is familiar,isn't it?yeah,if you had took part in the "Rooki ...

  8. Django Rest Framework(阿奇)

    Django Rest Framework 一. 什么是RESTful REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中 ...

  9. Docker入门笔记(1)

    Docker入门笔记(1) 1.安装Docker yum -y install docker-ce 2.查看Docker版本 [root@localhost ~]# docker -v Docker ...

  10. AR和VR的区别到底在哪?

    AR是Augmented Reality的字母缩写,中文名字是“增强现实”,是一种全新人机交互技术.通过AR技术,让参与者与虚拟对象进行实时互动,从而获得一种奇妙的视觉体验,而且能够突破空间.时间以及 ...