最近在看context底层源码时发现了一个奇怪的用法:struct里边嵌入interface,struct又没有完全实现interface的所有接口,以前真心没注意到这种用法,只见过interface嵌套interface的,决定提笔记录一下。
直接上源码吧:src\context\context.go
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key interface{}) interface{}
}
cancelCtx 结构体的定义和具体实现
type cancelCtx struct {
Context
mu sync.Mutex // protects following fields
done atomic.Value // of chan struct{}, created lazily, closed by first cancel call
children map[canceler]struct{} // set to nil by the first cancel call
err error // set to non-nil by the first cancel call
}
func (c *cancelCtx) Value(key interface{}) interface{} {
if key == &cancelCtxKey {
return c
}
return c.Context.Value(key)
}
func (c *cancelCtx) Done() <-chan struct{} {
d := c.done.Load()
if d != nil {
return d.(chan struct{})
}
c.mu.Lock()
defer c.mu.Unlock()
d = c.done.Load()
if d == nil {
d = make(chan struct{})
c.done.Store(d)
}
return d.(chan struct{})
}
func (c *cancelCtx) Err() error {
c.mu.Lock()
err := c.err
c.mu.Unlock()
return err
}
timerCtx 结构体的定义和具体实现
type timerCtx struct {
cancelCtx
timer *time.Timer // Under cancelCtx.mu.
deadline time.Time
}
func (c *timerCtx) Deadline() (deadline time.Time, ok bool) {
return c.deadline, true
}
Context接口有4个方法,但是cancelCtx只实现了3个方法,Deadline()它并没有实现,而timerCtx只实现了Deadline(),其他3个并没有实现。
在我的认知当中没见过这种写法,实现一个接口就是实现这个接口的所有方法,比如源码中的emptyCtx
type emptyCtx int
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
return
}
func (*emptyCtx) Done() <-chan struct{} {
return nil
}
func (*emptyCtx) Err() error {
return nil
}
func (*emptyCtx) Value(key interface{}) interface{} {
return nil
}
func (e *emptyCtx) String() string {
switch e {
case background:
return "context.Background"
case todo:
return "context.TODO"
}
return "unknown empty Context"
}
var (
background = new(emptyCtx)
todo = new(emptyCtx)
)
当时看到这种用法,直接懵逼了,还是自己基础不牢。。。。
嵌入interface作为struct的一个匿名成员,就可以假设这个struct就是此成员interface的一个实现,而不管struct是否已经实现interface所定义的函数。
type Student interface {
Run()
Walk()
}
type Pupil struct {
age int
Student
}
func NewPupil(age int) *Pupil{
return &Pupil{age: age}
}
//func (p *Pupil) Run() {
//
//}
//
//func (p *Pupil) Walk(){
//
//}
func main(){
p := NewPupil(100)
var s Student = p
fmt.Printf("%#v\n",s)
}
struct Pupil没有实现interface中的任何函数,只是在声明的时候把Student作为一个匿名成员,main函数能正常运行并没有报错,说明p确实被认为是Student的具体实现。
既然没有实现函数,那如何调用接口尼?答案就是 没有实现肯定是不能调用,一旦调用就crash。只能调用已经实现的函数。上边注释掉的 Run()和Walk() 放开哪个,s就可以调用哪个。。。