最近在看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就可以调用哪个。。。