如果某个函数的入参是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()
}
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"
    }
}
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
    }
v interface{}

在golang中,interface也是一个结构体,记录了2个指针:

  • 指针1,指向该变量的类型
  • 指针2,指向该变量的value
type rtype structtyp *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    [100000]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)
}
typ *rtypeword unsafe.Pointer
w := os.Stdout
A *os.File interface value
A *os.File interface value

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