-
接口型函数
:-
// 定义接口 type Getter interface {Get(key string) ([]byte, error) }// 定义函数 type GetterFunc func(key string) ([]byte, error)// 实现接口 func (f GetterFunc) Get(key string) ([]byte, error) {return f(key) }
-
价值:能将普通的函数类型作为参数,也能将结构体作为参数,使用更为灵活
-
例如:
-
// 若GetFromSource定义如下,需要传一个Getter作为参数 func GetFromSource(getter Getter, key string) []byte // 1.传函数(匿名函数和非匿名函数,下面是匿名) // 将函数类型转换为GetterFunc,这是实现了Getter接口的,可以传 GetFromSource(GetterFunc(func(key string) ([]byte, error) {return []byte(key), nil }), "hello") // 2.传结构体 type DB struct{ url string} func (db *DB) Get(key string) ([]byte, error) {// ...return []byte(v), nil } func main() {GetFromSource(new(DB), "hello") }
-
-
net/http
包下的Handler
就是使用这种特性-
type Handler interface {ServeHTTP(ResponseWriter, *Request) } type HandlerFunc func(ResponseWriter, *Request)func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {f(w, r) }
-
-
-
sync.Mutex
:Go 语言标准库提供的一个互斥锁,当一个协程(goroutine)获得了这个锁的拥有权后,其它请求锁的协程(goroutine) 就会阻塞在Lock()
方法的调用上,直到调用Unlock()
锁被释放。 -
reflect.DeepEqual
()- 对于基本数据类型(整数、布尔、字符串),与
==
相同 - 可以比较数组、切片、结构体、map、接口等是否相同
- 对于切片,必须切片长度相等且顺序相同,元素相同
- 对于基本数据类型(整数、布尔、字符串),与
-
day2
由四个文件组成,分别是lru.go
、byteview.go
、cache.go
、geecache.go
-
lru.go
:lru
缓存淘汰策略 -
byteview.go
:缓存值,实现了Value
接口 -
cache.go
:并发控制 -
geecache.go
:与外部交互,在缓存未命中时去查找数据源 -
cache.go
将day1
中的lru
加入了锁机制,实现并发下的互斥访问,geecache.go
中实现了Group
结构体,其中包含cache
和回调函数,在cache
未命中时会调用回调函数查找数据库中的内容,同时,使用map
结构分配多个缓存,用name
进行区分,每个Group
有一个唯一的name
(例如学生成绩和学生课程的缓存使用不同的name区分) -
代码
// --------------------------------------------------------------------------------------- // ByteView.go 缓存元素的抽象 package gee// 只读数据结构 表示缓存值,实现了Value接口 type ByteView struct {b []byte }func (v ByteView) Len() int {return len(v.b) }func (v ByteView) ByteSlice() []byte {return cloneBytes(v.b) }func cloneBytes(b []byte) []byte {c := make([]byte, len(b))copy(c, b)return c }func (v ByteView) String() string {return string(v.b) } // cache.go 对day1中的lru加上并发控制 package gee // --------------------------------------------------------------------------------------- // 实现并发控制 import ("sync" )type cache struct {mu sync.Mutexlru *CachecacheBytes int64 }func (c *cache) add(key string, value ByteView) {c.mu.Lock()defer c.mu.Unlock()if c.lru == nil { // 延迟初始化c.lru = New(c.cacheBytes, nil)}c.lru.Add(key, value) }func (c *cache) get(key string) (value ByteView, ok bool) {c.mu.Lock()defer c.mu.Unlock()if c.lru == nil {return}if v, ok := c.lru.Get(key); ok {return v.(ByteView), ok}return } // --------------------------------------------------------------------------------------- // geecache.go 与源数据库进行交互 package gee// 实现与外部交互 import ("fmt""sync" )type Getter interface {Get(key string) ([]byte, error) }type GetterFunc func(key string) ([]byte, error)// 接口型函数 func (f GetterFunc) Get(key string) ([]byte, error) {return f(key) }type Group struct {name string // 缓存名称getter Getter // 回调函数mainCache cache // 缓存 }var (mu sync.Mutexgroups = make(map[string]*Group) )func NewGroup(name string, cacheBytes int64, getter Getter) *Group {if getter == nil {panic("Getter nil")}mu.Lock()defer mu.Unlock()g := &Group{name: name,getter: getter,mainCache: cache{cacheBytes: cacheBytes},}groups[name] = greturn g }func GetGroup(name string) *Group {mu.Lock()defer mu.Unlock()g := groups[name]return g }func (g *Group) Get(key string) (ByteView, error) {if key == "" {return ByteView{}, fmt.Errorf("key is nil")}if v, ok := g.mainCache.get(key); ok {fmt.Println("Gee Cache hit")return v, nil}return g.load(key) }func (g *Group) load(key string) (Value ByteView, err error) {return g.getLocally(key) }// 调用回调函数,去源数据库查找内容 func (g *Group) getLocally(key string) (ByteView, error) { bytes, err := g.getter.Get(key)if err != nil {return ByteView{}, err}value := ByteView{b: cloneBytes(bytes)}g.add(key, value)return value, nil}func (g *Group) add(key string, value ByteView) {g.mainCache.add(key, value) }
-