首先,我们来看一个例子

type Stringer interface {
    String() string
}
type String struct {
    data string
}
func (s *String) String() string {
    return s.data
}

上面是类型,然后

func GetString() *String {
    return nil
}
func CheckString(s Stringer) bool {
    return s == nil
}
func main() {
    println(CheckString(GetString()))
}
CheckString

需要强调的是,本篇文章仅仅适用于golang。

类型转换

官方文档明确说明了怎么判断类型T是否可以转换成V,正常来说,T要转换成V必需显式声明。

func check64(v int64){}
func check(v int){}
a := 5
b := int64(10)
check64(int64(a))
check(int(b))
check64(a) // panic

不过,如果在满足Assignability的情况下,就可以在没有显式声明的情况下自动进行类型转换
其中,比较容易被忽略的是这两条:

  1. x is the predeclared identifier nil and T is a pointer,function,slice,map,channel,or interface type.
  2. x is an untyped constant representable by a value of type T.
const a = 5
func check64(v int64){}
func checkSlice(v []int){}
check64(a) // -> check64(int64(a))
check64(1024) // -> check64(int64(1024))
checkSlice(nil) // -> checkSlice([]int(nil))
Integer literalsinteger constant

分析

当了解之后,再看我刚开始给的例子

func GetString() *String {
    return nil
}
println(interface{}(GetString()))
*String(nil)
CheckString
func CheckString(s Stringer) bool {
    return s == nil
}
nilStringer(nil)(0x0,0x0)

是不是感到很奇怪,print打印出来的第一个是类型的指针,为什么是0?首先,一个变量会有一个动态类型和静态类型,如果不是interface的话,静态类型和动态类型是一样的,当interface时,静态类型是interface的值,而动态类型确是他储存的值的实际类型。而print打印的是动态类型,由于这里他的值为0,动态类型也肯定为0.

CheckString(GetString())*String(nil)(nil)dynamic typedynamic value

如何不踩坑

虽然例子看起来很无厘头,但实际上这个比较容易踩坑的,特别是在想要作死的时候...

type SpecError struct {
    err Error
}
func NewSpecError(err error) *SpecError {
    if err == nil {
        return nil
    }
    return &SpecError{err}
}
func (se *SpecError) Error() string {
    return se.err.Error()
}
func GetobjByID(id string) (*Obj,error) {
    obj,err := xxxxx(id)
    return obj,NewSpecError(err)

}
func main(){
    obj,err := GetobjByID("123")
    if err != nil {
        panic(err)
    }
    。。。
}
GetobjByIDif err != nil

思考

type RouterString func() string
type RouterBytes func() []byte
func AddRouter(router interface{}) {
    switch router := router.(type) {
    case RouterString:
        println("string")
    case RouterBytes:
        println("bytes")
    default:
        println("unkNown types")
    }
}
func main() {
    AddRouter(func() string{
        println("hello?")
    })
}

这段代码哪里错了?怎么改?