首先需要一个数据结构:
type Cache struct {
maxBytes int64
nbytes int64
ll *list.List
cache map[string]*list.Element
OnEvicted func(key string,value Value)
}
maxBytes:缓存最大存储字节
nbytes:当前存储字节
ll:数据结构
cache:元素
OnEvicted:元素被丢弃后的操作
注意:存了两份,一份在ll链表中,一份在cache中。
定义元素的键值对类型:
type entry struct {
key string
value Value
}
元素值类型所占字节获取函数:
type Value interface {
Len() int
}
创建操作:
func New(maxBytes int64, onEvicted func(key string,value Value)) *Cache {
return &Cache{
maxBytes: maxBytes,
ll: list.New(),
cache: make(map[string]*list.Element)
OnEvicted: onEvicted,
}
}
缓存的大小:
func (c *Cache) Len() int {
return c.ll.Len()
}
被淘汰的元素操作:
func (c *Cache) RemoveOldest() {
ele := c.ll.Back()
if ele != nil {
c.ll.Remove(ele)
kv := ele.Value.(*entry)
c.nbytes -= int64(len(kv.key)) + int64(kv.value.Len())
if c.OnEvicted != nil {
c.OnEvicted(kv.key, kv.value)
}
}
}
添加元素:
func (c *Cache) Add(key string, value Value) {
if ele, ok := c.cache[key]; ok {
c.ll.MoveToFront(ele)
kv := ele.Value.(*entry)
c.nbytes += int64(value.Len()) - int64(kv.value.Len())
kv.value = value
} else {
ele := c.ll.PushFront(entry{key: key, value: value})
c.cache[key] = ele
c.nbytes += int64(len(key)) + int64(value.Len())
}
for c.maxBytes != 0 && c.nbytes > c.maxBytes {
c.RemoveOldest()
}
}
获取元素:
func (c *Cache) Get(key string) (value Value, ok bool) {
if ele, ok := c.cache[key]; ok {
c.ll.MoveToFront(ele)
kv := ele.Value.(*entry)
return kv.value, ok
}
return
}
全部代码
package lru
import "container/list"
type Cache struct {
maxBytes int64
nbytes int64
ll *list.List
cache map[string]*list.Element
OnEvicted func(key string,value Value)
}
type entry struct {
key string
value Value
}
type Value interface {
Len() int
}
func New(maxBytes int64, onEvicted func(key string,value Value)) *Cache {
return &Cache{
maxBytes: maxBytes,
ll: list.New(),
cache: make(map[string]*list.Element)
OnEvicted: onEvicted,
}
}
func (c *Cache) Add(key string, value Value) {
if ele, ok := c.cache[key]; ok {
c.ll.MoveToFront(ele)
kv := ele.Value.(*entry)
c.nbytes += int64(value.Len()) - int64(kv.value.Len())
kv.value = value
} else {
ele := c.ll.PushFront(entry{key: key, value: value})
c.cache[key] = ele
c.nbytes += int64(len(key)) + int64(value.Len())
}
for c.maxBytes != 0 && c.nbytes > c.maxBytes {
c.RemoveOldest()
}
}
func (c *Cache) Get(key string) (value Value, ok bool) {
if ele, ok := c.cache[key]; ok {
c.ll.MoveToFront(ele)
kv := ele.Value.(*entry)
return kv.value, ok
}
return
}
func (c *Cache) RemoveOldest() {
ele := c.ll.Back()
if ele != nil {
c.ll.Remove(ele)
kv := ele.Value.(*entry)
c.nbytes -= int64(len(kv.key)) + int64(kv.value.Len())
if c.OnEvicted != nil {
c.OnEvicted(kv.key, kv.value)
}
}
}
func (c *Cache) Len() int {
return c.ll.Len()
}