groupcache源码分析6:sink.go
sink.go文件实际上也是提供数据结构,在ByteView之上做了一层封装。
Sink接口,提供三个set方法和一个view方法,view方法返回ByteView。
type Sink interface { SetString(s string) error SetBytes(v []byte) error SetProto(m proto.Message) error view() (ByteView, error) }[]byte类型拷贝。
func cloneBytes(b []byte) []byte { c := make([]byte, len(b)) copy(c, b) return c }setSinkView方法,将一个ByteView内容设置到Sink中。注意这里viewSetter的使用,通过它去断言s是否包含setView方法。
func setSinkView(s Sink, v ByteView) error { type viewSetter interface { setView(v ByteView) error } if vs, ok := s.(viewSetter); ok { return vs.setView(v) } if v.b != nil { return s.SetBytes(v.b) } return s.SetString(v.s) }文件中定义了不少实现Sink接口的结构体,但是代码中实际只用到了allocBytesSink。我们这里只单独分析一下它。创建方法和allocBytesSink结构体定义。
func AllocatingByteSliceSink(dst *[]byte) Sink { return &allocBytesSink{dst: dst} } type allocBytesSink struct { dst *[]byte //这里有一个疑问,此属性有什么用呢?看代码它还是一个新分配地址,但是view方法并不需要它啊。 v ByteView }view方法没啥可说的。值得注意得是另一个setView方法,我们可以使用第2步中的setSinkView方法来赋值。还有一个有意思的点,如果v存储了[]byte,那么cloneBytes方法创建出了一个新的切片赋值,否则通过string转[]byte生成一个新的切片赋值(一个新知识点:[]byte的变量赋值指向同一个地址,string和[]byte的转换是数据复制)。
func (s *allocBytesSink) view() (ByteView, error) { return s.v, nil } func (s *allocBytesSink) setView(v ByteView) error { if v.b != nil { *s.dst = cloneBytes(v.b) } else { *s.dst = []byte(v.s) } s.v = v return nil }使用[]byte设置s和v
func (s *allocBytesSink) setBytesOwned(b []byte) error { if s.dst == nil { return errors.New("nil AllocatingByteSliceSink *[]byte dst") } *s.dst = cloneBytes(b) // clone后赋值,如果b被更改,这里的dst不会变 s.v.b = b s.v.s = "" return nil }通过proto的Message类型和[]byte类型进行赋值,内部均调用了上面setBytesOwned方法
func (s *allocBytesSink) SetProto(m proto.Message) error { b, err := proto.Marshal(m) if err != nil { return err } return s.setBytesOwned(b) } func (s *allocBytesSink) SetBytes(b []byte) error { return s.setBytesOwned(cloneBytes(b)) }string类型的赋值
func (s *allocBytesSink) SetString(v string) error { if s.dst == nil { return errors.New("nil AllocatingByteSliceSink *[]byte dst") } *s.dst = []byte(v) s.v.b = nil s.v.s = v return nil }