在示例中,我们定义一个interface名为Stringer,同时定义一个符合其定义的Binary类型:
type Stringer interface {
String() string
}
type Binary uint64
func (i Binary) String() string {
return strconv.Uitob64(i.Get(), 2)
}
func (i Binary) Get() uint64 {
return uint64(i)
}
func ToString(any interface{}) string {
if v, ok := any.(Stringer); ok {
return v.String()
}
switch v := any.(type) {
case int:
return strconv.Itoa(v)
case float:
return strconv.Ftoa(v, 'g', -1)
}
return "???"
}
复制代码
如果将一个Binary类型的变量b b=Binary(200)赋值给一个interface类型的值,排除内存优化的因素,将会形成以下的结构:
可以看到,interface变量由代表类型的itable和代表值的data来表示<itable, data>。 itable中保留的仅有Stringer类型包含的方法,其余Binary的方法并不在interface变量中可见。 data变量保存的是原数据b的一份拷贝,而不是简单的引用。
Golang中的nil:
由定义可知:
复制代码
nil is a predeclared identifier representing the zero value for a pointer, channel, func, interface, map, or slice type.
判断interface为nil:
只有当interface为零值,即<itable, data>=<nil, nil>时,才能等于nil。
在上面的例中,如有有这样一个方法:
func isNil(s Stringer) {
defer func() {
if e := recover(); e != nil {
fmt.Printf("panic in isNil(), err:%v\n", e)
}
}()
if s == nil {
fmt.Printf("judge1:s(%v) == nil\n", s)
return
}
if reflect.ValueOf(s).IsNil() {
fmt.Printf("judge2:s(%v) reflect nil\n", s)
return
}
fmt.Printf("s(%v) pass\n", s)
}