面试题答案
一键面试减少类型断言开销
- 类型参数(Go 1.18+):使用泛型来减少类型断言。定义缓存时,使用类型参数指定缓存数据的类型,这样在获取和设置数据时不需要进行类型断言。
- 接口方法约束:如果使用空接口,通过定义接口方法来约束缓存数据的行为,在获取数据时,可以直接调用接口方法,减少不必要的类型断言。
缓存数据过期和淘汰策略
- 过期策略:在缓存数据结构中添加一个过期时间字段,每次获取数据时检查当前时间是否超过过期时间,超过则删除该数据。
- 淘汰策略:常见的淘汰策略有LRU(最近最少使用)、LFU(最不经常使用)等。可以通过维护一个链表或使用哈希表结合链表的方式实现LRU,对于LFU可以使用哈希表记录每个数据的访问频率。
Go代码示例
package main
import (
"container/list"
"fmt"
"time"
)
// 定义缓存项结构
type CacheItem struct {
key string
value interface{}
expiration time.Time
}
// 定义缓存结构
type Cache struct {
items map[string]*list.Element
lruList *list.List
capacity int
expiration time.Duration
}
// 创建新的缓存
func NewCache(capacity int, expiration time.Duration) *Cache {
return &Cache{
items: make(map[string]*list.Element),
lruList: list.New(),
capacity: capacity,
expiration: expiration,
}
}
// 设置缓存
func (c *Cache) Set(key string, value interface{}) {
if elem, exists := c.items[key]; exists {
c.lruList.MoveToFront(elem)
elem.Value.(*CacheItem).value = value
elem.Value.(*CacheItem).expiration = time.Now().Add(c.expiration)
return
}
item := &CacheItem{
key: key,
value: value,
expiration: time.Now().Add(c.expiration),
}
elem := c.lruList.PushFront(item)
c.items[key] = elem
if c.lruList.Len() > c.capacity {
c.removeOldest()
}
}
// 获取缓存
func (c *Cache) Get(key string) (interface{}, bool) {
if elem, exists := c.items[key]; exists {
item := elem.Value.(*CacheItem)
if time.Now().After(item.expiration) {
c.remove(elem)
return nil, false
}
c.lruList.MoveToFront(elem)
return item.value, true
}
return nil, false
}
// 删除最久未使用的项
func (c *Cache) removeOldest() {
elem := c.lruList.Back()
if elem != nil {
c.remove(elem)
}
}
// 删除指定项
func (c *Cache) remove(elem *list.Element) {
c.lruList.Remove(elem)
item := elem.Value.(*CacheItem)
delete(c.items, item.key)
}
你可以这样使用上述缓存:
func main() {
cache := NewCache(2, 2*time.Second)
cache.Set("key1", "value1")
cache.Set("key2", "value2")
value, exists := cache.Get("key1")
if exists {
fmt.Println("Value for key1:", value)
}
cache.Set("key3", "value3")
_, exists = cache.Get("key2")
if!exists {
fmt.Println("Key2 was evicted")
}
time.Sleep(3 * time.Second)
_, exists = cache.Get("key1")
if!exists {
fmt.Println("Key1 has expired")
}
}
此代码实现了一个简单的带有过期和LRU淘汰策略的缓存。Set
方法用于设置缓存项,Get
方法用于获取缓存项并处理过期,removeOldest
方法实现了LRU淘汰策略。