cache

package module
v1.5.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 23, 2025 License: Apache-2.0 Imports: 5 Imported by: 0

README

cache 是一个带索引带超时的缓存库

目的在于优化代码结构,提供了若干实践。

example

实践1 定义泛型函数

1.18 已经发布一段实践了。通过泛型函数。我们可以减少循环的使用,优化代码结构。下面分享几个泛型函数和代码上的实践。

Filter 函数

// Filter filter one slice
func Filter[T any](objs []T, filter func(obj T) bool) []T {
	res := make([]T, 0, len(objs))
	for i := range objs {
		ok := filter(objs[i])
		if ok {
			res = append(res, objs[i])
		}
	}
	return res
}
// 测试[]int
func TestFilter(t *testing.T) {
	ans := []int{2, 4, 6}
	a := []int{1, 2, 3, 4, 5, 6}
	b := Filter(a, func(i int) bool {
        return i%2 == 0
	})
	require.Equal(t, ans, b)
	spew.Dump(b)
}
// 结果
=== RUN   TestFilter
([]int) (len=3 cap=6) {
 (int) 2,
 (int) 4,
 (int) 6
}
--- PASS: TestFilter (0.00s)
PASS

// NoSpace is filter func for strings
func NoSpace(s string) bool {
	return strings.TrimSpace(s) != ""
}
// 测试[]sting
func TestFilterNoSpace(t *testing.T) {
	ans1 := []string{"1", "2", "3"}
	a := []string{"", "1", "", "2", "", "3", ""}
	b := Filter(a, NoSpace)
	require.Equal(t, ans1, b)
	spew.Dump(b)
}
// 结果
=== RUN   TestFilterNoSpace
([]string) (len=3 cap=7) {
 (string) (len=1) "1",
 (string) (len=1) "2",
 (string) (len=1) "3"
}
--- PASS: TestFilterNoSpace (0.00s)
PASS

Map 函数

// Map one slice
func Map[T any, K any](objs []T, mapper func(obj T) ([]K, bool)) []K {
	res := make([]K, 0, len(objs))
	for i := range objs {
		others, ok := mapper(objs[i])
		if ok {
			res = append(res, others...)
		}
	}
	return res
}
// 测试 []int -> []string
func TestMap(t *testing.T) {
	ans := []string{"2", "4", "6", "end"}
	a := []int{1, 2, 3, 4, 5, 6}
	b := Map(a, func(i int) ([]string, bool) {
		if i == 6 {
			return []string{fmt.Sprintf(`%v`, i), `end`}, true
		}
		if i%2 == 0 {
			return []string{fmt.Sprintf(`%v`, i)}, true
		} else {
			return nil, false
		}
	})
	require.Equal(t, ans, b)
	spew.Dump(b)
}
// 结果
=== RUN   TestMap
([]string) (len=4 cap=6) {
 (string) (len=1) "2",
 (string) (len=1) "4",
 (string) (len=1) "6",
 (string) (len=3) "end"
}
--- PASS: TestMap (0.00s)
PASS

First 函数

// First make return first for slice
func First[T any](objs []T) (T, bool) {
	if len(objs) > 0 {
		return objs[0], true
	}
	return *new(T), false
}

func TestFirstInt(t *testing.T) {
	ans1, ans2 := 1, 0
	a := []int{1, 2, 3, 4, 5, 6}
	b, ok := First(a)
	require.True(t, ok)
	require.Equal(t, ans1, b)
	spew.Dump(b)
	c := []int{}
	d, ok := First(c)
	require.False(t, ok)
	require.Equal(t, ans2, d)
	spew.Dump(d)
}
// result
=== RUN   TestFirstInt
(int) 1
(int) 0
--- PASS: TestFirstInt (0.00s)
PASS

func TestFirstString(t *testing.T) {
	ans1, ans2 := "1", ""
	a := []string{"1", "2", "3", "4", "5", "6"}
	b, ok := First(a)
	require.True(t, ok)
	require.Equal(t, ans1, b)
	spew.Dump(b)
	c := []string{}
	d, ok := First(c)
	require.False(t, ok)
	require.Equal(t, ans2, d)
	spew.Dump(d)
}
// result
=== RUN   TestFirstString
(string) (len=1) "1"
(string) ""
--- PASS: TestFirstString (0.00s)
PASS

实践2 带超时的cache

  • 某些情况下,我们删除过期的cache, 通过利用带超时的cache,简化代码
  • cache 结构 github.com/weapons97/cache/cache.go
// 用辅助map删除
if apiRet.TotalCount > 0 {
 var hc sync.Map
 for _, h := range apiRet.Hcis {
  hc.Store(h.HostID, h)
  hostCpu.Store(h.HostID, h)
 }
 hostCpu.Range(func(key, _ interface{}) bool {
  _, ok := hc.Load(key)
  if !ok {
   hostCpu.Delete(key)
  }
  return true
 })
}
// 直接设置,过期的key 会删除
for _, h := range apiRet.Hcis {
	hostCpu.Set(h.HostID, h)
}
func TestNewCache(t *testing.T) {
	c := NewCache(WithTTL[string, int](time.Second))
	b := 1
	c.Set(`a`, b)
	d, ok := c.Get(`a`)
	require.True(t, ok)
	require.Equal(t, b, d)
	time.Sleep(time.Second)
	d, ok = c.Get(`a`)
	require.False(t, ok)
	// 超时返回0值
	require.Equal(t, d, 0)
}

实践3 集合操作

通过 set 做集合,可以给集合去重。可以给结合相并,想交,等操作。 set 结构 github.com/weapons97/cache/set.go

func TestSetUnion(t *testing.T) {
	s := NewSet[string]()
	s.Add(`a`)
	s.Add(`b`)
	s2 := NewSet[string]()
	s2.Add(`b`)
	s2.Add(`d`)
	s3 := s.Union(s2)
	wantS3 := []string{`a`, `b`, `d`}

	ans := s3.List()
	sort.Strings(ans)
	require.Equal(t, wantS3, ans)
	spew.Dump(s.List(), s2.List(), s3.List())
}

func TestSetJoin(t *testing.T) {
	s := NewSet[string]()
	s.Add(`a`)
	s.Add(`b`)
	s2 := NewSet[string]()
	s2.Add(`b`)
	s2.Add(`d`)
	s3 := s.Join(s2)
	wantS3 := []string{`b`}

	ans := s3.List()
	sort.Strings(ans)
	require.Equal(t, wantS3, ans)
	spew.Dump(s.List(), s2.List(), s3.List())
}

func TestSetJoinLeft(t *testing.T) {
	s := NewSet[string]()
	s.Add(`a`)
	s.Add(`b`)
	s2 := NewSet[string]()
	s2.Add(`b`)
	s2.Add(`d`)
	s3 := s.JoinLeft(s2)
	wantS3 := []string{`a`, `b`}
	ans := s3.List()
	sort.Strings(ans)

	require.Equal(t, wantS3, ans)
	spew.Dump(s.List(), s2.List(), s3.List())
}

func TestSetJoinRight(t *testing.T) {
	s := NewSet[string]()
	s.Add(`a`)
	s.Add(`b`)
	s2 := NewSet[string]()
	s2.Add(`b`)
	s2.Add(`d`)
	s3 := s.JoinRight(s2)
	wantS3 := []string{`b`, `d`}
	ans := s3.List()
	sort.Strings(ans)
	require.Equal(t, wantS3, ans)
	spew.Dump(s.List(), s2.List(), s3.List())
}

func TestSetSub(t *testing.T) {
	s := NewSet[string]()
	s.Add(`a`)
	s.Add(`b`)
	s2 := NewSet[string]()
	s2.Add(`b`)
	s2.Add(`d`)
	s3 := s.Sub(s2)
	wantS3 := []string{`a`}
	ans := s3.List()
	sort.Strings(ans)
	require.Equal(t, wantS3, ans)
	spew.Dump(s.List(), s2.List(), s3.List())
}

  • 通过set 去重
// ShowImageInManifest 抓取 manifest 中imgs
func ShowImageInManifest(manifest string) (imgs []string) {
	rx := regImages.FindAllStringSubmatch(manifest, -1)
	set := cache.NewSet[string]()
	for i := range rx {
		for j := range rx[i] {
			if strings.HasPrefix(rx[i][j], `image:`) {
				continue
			}
			tx0 := strings.TrimSpace(rx[i][j])
			tx1 := strings.Trim(tx0, `'`)
			tx2 := strings.Trim(tx1, `"`)
			set.Add(tx2)
		}
	}
	imgs = set.List()
	return imgs
}

4 带索引的cache

  • 某些情况下,我们可能根据cache 的某个元素对cache进行遍历,这时候如果给cache 加上索引结构,可以对遍历加速。
  • index 结构 github.com/weapons97/cache/index.go
type Person struct {
	id       string
	lastName string
	fullName string
	country  string
}

const (
	IndexByLastName = `IndexByLastName`
	IndexByCountry  = `IndexByCountry`
)

func (p *Person) Indexs() map[string]IndexFunc {
	return map[string]IndexFunc{
		IndexByLastName: func(indexed any) (key []string) {
			ci := indexed.(*Person)
			return []string{ci.lastName}
		},
		IndexByCountry: func(indexed any) (key []string) {
			ci := indexed.(*Person)
			return []string{ci.country}
		},
	}
}

func (p *Person) ID() (mainKey string) {
	return p.id
}
// 测试数据
var (
	p1 = &Person{
		id:       `1`,
		lastName: "魏",
		fullName: "魏鹏",
		country:  `China`,
	}
	p2 = &Person{
		id:       `2`,
		lastName: "魏",
		fullName: "魏无忌",
		country:  `America`,
	}
	p3 = &Person{
		id:       `3`,
		lastName: "李",
		fullName: "李云",
		country:  `China`,
	}
	p4 = &Person{
		id:       `4`,
		lastName: "黄",
		fullName: "黄帅来",
		country:  `China`,
	}
	p5 = &Person{
		id:       `5`,
		lastName: "Cook",
		fullName: "TimCook",
		country:  `America`,
	}
	p6 = &Person{
		id:       `6`,
		lastName: "Jobs",
		fullName: "SteveJobs",
		country:  `America`,
	}
	p7 = &Person{
		id:       `7`,
		lastName: "Musk",
		fullName: "Elon Musk",
		country:  `America`,
	}
)
func TestIndexByCountry(t *testing.T) {
	tests := []struct {
		name      string
		indexName string
		indexKey  string
		res       []*Person
	}{
		{`IndexByCountry`,
			IndexByCountry,
			`China`,
			[]*Person{p1, p3, p4},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			rs := index.Search(tt.indexName, tt.indexKey)
			rx := rs.InvokeAll()
			require.Len(t, rx, len(tt.res))
			if !reflect.DeepEqual(rx, tt.res) {
				t.Errorf("got %v, want %v", rx, tt.res)
			}
		})
	}
}

Documentation

Overview

Package cache ============================================================================= # Author: peng.wei # Email: [email protected] # Version: 0.0.1 # LastChange: 20211214 # History: =============================================================================

Package cache ============================================================================= # Author: peng.wei # Email: [email protected] # Version: 0.0.1 # LastChange: 20211214 # History: =============================================================================

Package cache ============================================================================= # Author: peng.wei # Email: [email protected] # Version: 0.0.1 # LastChange: 20211214 # History: =============================================================================

Package cache ============================================================================= # Author: peng.wei # Email: [email protected] # Version: 0.0.1 # LastChange: 20211214 # History: =============================================================================

Index

Constants

This section is empty.

Variables

View Source
var CacheManagerFactory = func() CacheManager {
	return defaultManager
}

CacheManagerFactory 返回 CacheManager 的方法

View Source
var (
	// Forever 永远不超时
	Forever = time.Hour * 24 * 365 * 100
)

Functions

func IndexGet

func IndexGet[T any](i Indexed) (rx T, ok bool)

func PowerSet added in v1.4.0

func PowerSet[T any](s []T) [][]T

PowerSet 求幂集

Types

type Cache

type Cache[K comparable, V any] struct {
	// contains filtered or unexported fields
}

Cache 是一个带超时的缓存, 超时的元素会获取不到并删除(默认情况下)

func NewCache

func NewCache[K comparable, V any](opts ...Option[K, V]) *Cache[K, V]

NewCache 创建新cache

func NewCacheInits added in v1.3.0

func NewCacheInits[K comparable, V any](inits map[K]V, opts ...Option[K, V]) *Cache[K, V]

NewCacheInits 创建新cache

func (*Cache[K, V]) Clean

func (c *Cache[K, V]) Clean()

Clean 会被cache manager 定期调用删除过期的元素

func (*Cache[K, V]) Clear added in v1.1.2

func (c *Cache[K, V]) Clear()

Clear 清空cache

func (*Cache[K, V]) Del

func (c *Cache[K, V]) Del(k K)

Del 根据key 删除 cache

func (*Cache[K, V]) Get

func (c *Cache[K, V]) Get(req K) (V, bool)

Get 根据key获得value 超时或者空第二个返回值为false,否则返回true

func (*Cache[K, V]) Has added in v1.1.2

func (c *Cache[K, V]) Has(k ...K) bool

Has 是否包含

func (*Cache[K, V]) HasAny added in v1.5.2

func (c *Cache[K, V]) HasAny(k ...K) bool

HasAny 是否包含任何一个键

func (*Cache[K, V]) IsEmpty added in v1.1.2

func (c *Cache[K, V]) IsEmpty() bool

IsEmpty 是否为空

func (*Cache[K, V]) Len

func (c *Cache[K, V]) Len() int

Len 返回cache 长度

func (*Cache[K, V]) List

func (c *Cache[K, V]) List() ([]K, []V)

List func list k and list v

func (*Cache[K, V]) ListKey added in v1.2.0

func (c *Cache[K, V]) ListKey() []K

ListKey func list k

func (*Cache[K, V]) ListValue added in v1.2.0

func (c *Cache[K, V]) ListValue() []V

ListValue func list v

func (*Cache[K, V]) Merge added in v1.1.2

func (c *Cache[K, V]) Merge(s *Cache[K, V])

Merge 合并cache

func (*Cache[K, V]) Name

func (c *Cache[K, V]) Name() string

Name return name of cache

func (*Cache[K, V]) Options

func (c *Cache[K, V]) Options() []Option[K, V]

Options 返回cache的选项

func (*Cache[K, V]) Range

func (c *Cache[K, V]) Range(fn func(k K, v V) bool)

Range 遍历cache

func (*Cache[K, V]) Remove added in v1.1.2

func (c *Cache[K, V]) Remove(k ...K)

Remove 根据key 删除 cache

func (*Cache[K, V]) Set

func (c *Cache[K, V]) Set(req K, values V)

Set 设置k,v

func (*Cache[K, V]) Size added in v1.1.2

func (c *Cache[K, V]) Size() int

Size 返回cache 长度

type CacheI

type CacheI interface {
	Clean()
	Name() string
}

CacheI 接口, 一个结构实现了CacheI 接口才可以被CacheManager 使用

type CacheManager

type CacheManager interface {
	Tasks()                  // CacheManager 的tasks 会定期执行
	RegisterCache(c CacheI)  // 注册cache
	Interval() time.Duration // 返回执行tasks的间隔
}

CacheManager 持有所有的cache 可以定时执行cache 的tasks

type IndexFunc

type IndexFunc func(indexed any) (keys []string)

IndexFunc 是Indexed元素的索引函数

type Indexed

type Indexed interface {
	Indexes() map[string]IndexFunc
	ID() (mainKey string)
}

Indexed 接口, 一个结构实现了Indexed 接口才可以被Indexer 使用

type Indexer

type Indexer[T Indexed] struct {
	// contains filtered or unexported fields
}

Indexer 是带索引的cache

func NewIndexer

func NewIndexer[T Indexed](ops ...Option[string, T]) *Indexer[T]

NewIndexer 创建一个带索引的cache

func (*Indexer[T]) Add added in v1.1.2

func (ix *Indexer[T]) Add(v ...T)

func (*Indexer[T]) Clear added in v1.1.2

func (ix *Indexer[T]) Clear()

func (*Indexer[T]) Del

func (ix *Indexer[T]) Del(v interface{})

Del 删除一个Indexed

func (*Indexer[T]) Get

func (ix *Indexer[T]) Get(id string) (v T, ok bool)

Get 根据id 查找Indexed

func (*Indexer[T]) Has added in v1.1.2

func (ix *Indexer[T]) Has(v ...T) bool

func (*Indexer[T]) IsEmpty added in v1.1.2

func (ix *Indexer[T]) IsEmpty() bool

func (*Indexer[T]) Len

func (ix *Indexer[T]) Len() int

Len 返回cache 长度

func (*Indexer[T]) List added in v1.1.1

func (ix *Indexer[T]) List() ([]string, []T)

List func list k and list v

func (*Indexer[T]) ListKey added in v1.2.0

func (ix *Indexer[T]) ListKey() []string

ListKey func list k

func (*Indexer[T]) ListValue added in v1.2.0

func (ix *Indexer[T]) ListValue() []T

ListValue func list v

func (*Indexer[T]) Merge added in v1.1.2

func (ix *Indexer[T]) Merge(s *Indexer[T])

func (*Indexer[T]) Pop added in v1.1.2

func (ix *Indexer[T]) Pop() T

func (*Indexer[T]) Range

func (ix *Indexer[T]) Range(fn func(k string, v T) bool)

Range 遍历Indexer

func (*Indexer[T]) Remove added in v1.1.2

func (ix *Indexer[T]) Remove(v ...T)

func (*Indexer[T]) Search

func (ix *Indexer[T]) Search(idxName string, key string) *SearchResult[T]

Search 根据索引函数查找Indexer

func (*Indexer[T]) Set

func (ix *Indexer[T]) Set(v T) bool

Set 设置值,v 必须和 Indexer 的type相同

func (*Indexer[T]) SetFromIndex

func (ix *Indexer[T]) SetFromIndex(idxName string) (*Set[string], error)

SetFromIndex 从indexName 创建一个Set

func (*Indexer[T]) Size added in v1.1.2

func (ix *Indexer[T]) Size() int

type InterfaceCache added in v1.1.2

type InterfaceCache[K comparable, V any] interface {
	Set(req K, values V)
	Remove(key ...K)
	Has(items ...K) bool
	HasAny(k ...K) bool
	Size() int
	Clear()
	IsEmpty() bool
	Range(fn func(s string, k K) bool)
	List() ([]K, []V)
	ListKey() []K
	ListValue() []V
	Merge(s *Cache[K, V])
}

InterfaceCache 是cache的接口

type InterfaceIndexer added in v1.1.2

type InterfaceIndexer[K Indexed] interface {
	Add(key ...K)
	Remove(key ...K)
	Pop() K
	Has(items ...K) bool
	Size() int
	Clear()
	IsEmpty() bool
	Range(fn func(s string, k K) bool)
	List() ([]string, []K)
	ListKey() []string
	ListValue() []K
	Merge(s *Indexer[K])
}

InterfaceIndexer 是Indexer的接口

type InterfaceSet

type InterfaceSet[K comparable] interface {
	Add(key ...K)
	Remove(key ...K)
	Pop() K
	Has(items ...K) bool
	HasAny(k ...K) bool
	Size() int
	Clear()
	IsEmpty() bool
	IsEqual(s *Set[K]) bool
	IsSubset(s *Set[K]) bool
	IsSuperset(s *Set[K]) bool
	Range(fn func(k K) bool)
	List() []K
	Copy() *Set[K]
	Merge(s *Set[K])
	Separate(t *Set[K])
}

InterfaceSet 是set的接口

type Option

type Option[K comparable, V any] func(*Cache[K, V])

Option cache 的选项

func WithName

func WithName[K comparable, V any](name string) Option[K, V]

WithName 设置cache名称

func WithNoManager

func WithNoManager[K comparable, V any]() Option[K, V]

WithNoManager 设置cache不受 cacheManager管理

func WithTTL

func WithTTL[K comparable, V any](ttl time.Duration) Option[K, V]

WithTTL 设置超时

type SearchResult

type SearchResult[T Indexed] struct {
	Res []T
	// contains filtered or unexported fields
}

SearchResult 是Indexer 根据索引函数查找的结果

func (*SearchResult[T]) Error

func (sr *SearchResult[T]) Error() error

Error 查找的错误

func (*SearchResult[T]) Failed

func (sr *SearchResult[T]) Failed() bool

Failed 查找是否成功

func (*SearchResult[T]) InvokeAll

func (sr *SearchResult[T]) InvokeAll() []T

InvokeAll 返回所有搜索结果

func (*SearchResult[T]) InvokeOne

func (sr *SearchResult[T]) InvokeOne() (rx T)

InvokeOne 拿一个结果就好

func (*SearchResult[T]) Range

func (sr *SearchResult[T]) Range(fn func(v T) bool)

Range 遍历所有搜索结果

type Set

type Set[K comparable] struct {
	// contains filtered or unexported fields
}

Set 是Set 型的cache 会多几个集合操作

func NewSet

func NewSet[K comparable](opts ...Option[K, struct{}]) *Set[K]

NewSet 新创建set

func NewSetInits

func NewSetInits[K comparable](inits []K, opts ...Option[K, struct{}]) *Set[K]

NewSetInits 新创建set

func (*Set[K]) Add

func (s *Set[K]) Add(key ...K)

Add 添加key

func (*Set[K]) Clear

func (s *Set[K]) Clear()

Clear 清空set

func (*Set[K]) Copy

func (s *Set[K]) Copy() *Set[K]

Copy 复制set

func (*Set[K]) Difference

func (s *Set[K]) Difference(o *Set[K], opts ...Option[K, struct{}]) *Set[K]

Difference godoc

func (*Set[K]) Get

func (s *Set[K]) Get(key K) bool

Get 查找key是否存在

func (*Set[K]) Has

func (s *Set[K]) Has(items ...K) bool

Has 已查找已传递的项目是否存在。如果未传递任何内容,则返回 false。对于多个项目,仅当所有项目都存在时,它才返回 true。

func (*Set[K]) HasAny added in v1.5.2

func (s *Set[K]) HasAny(items ...K) bool

HasAny 检查是否存在任何一个传递的项目。如果未传递任何内容,则返回 false。对于多个项目,只要有一个存在就返回 true。

func (*Set[K]) Intersection

func (s *Set[K]) Intersection(o *Set[K], opts ...Option[K, struct{}]) *Set[K]

Intersection 交集

func (*Set[K]) IsEmpty

func (s *Set[K]) IsEmpty() bool

IsEmpty 判断set是否为空

func (*Set[K]) IsEqual

func (s *Set[K]) IsEqual(o *Set[K]) bool

IsEqual 判断set是否相等

func (*Set[K]) IsSubset

func (s *Set[K]) IsSubset(o *Set[K]) (subset bool)

IsSubset 判断set是否为子集

func (*Set[K]) IsSuperset

func (s *Set[K]) IsSuperset(o *Set[K]) bool

IsSuperset 判断set是否为父集

func (*Set[K]) List

func (s *Set[K]) List() []K

List 列出元素

func (*Set[K]) Merge

func (s *Set[K]) Merge(o *Set[K])

Merge 合并set

func (*Set[K]) Pop

func (s *Set[K]) Pop() (res K)

func (*Set[K]) PowerSet added in v1.4.0

func (s *Set[K]) PowerSet(key ...K) (powerSet []*Set[K])

PowerSet 取幂集

func (*Set[K]) Range

func (s *Set[K]) Range(fn func(k K) bool)

Range 遍历set

func (*Set[K]) Remove

func (s *Set[K]) Remove(key ...K)

Remove 删除key

func (*Set[K]) Separate

func (s *Set[K]) Separate(t *Set[K])

Separate it's not the opposite of Merge. Separate removes the set items containing in t from set s. Please aware that

func (*Set[K]) Size

func (s *Set[K]) Size() int

Size 返回cache 长度

func (*Set[K]) Sub

func (s *Set[K]) Sub(o *Set[K], opts ...Option[K, struct{}]) *Set[K]

Sub 差集

func (*Set[K]) Union

func (s *Set[K]) Union(o *Set[K], opts ...Option[K, struct{}]) *Set[K]

Union 并集

type TimeValue

type TimeValue interface {
	Time() time.Time
}

TimeValue 是一个带有时间的值

type TimeoutValue

type TimeoutValue interface {
	Timeout() time.Time
}

TimeoutValue 是一个带有超时时间的值

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL