以下代码中,getFunc 只支持一个参数,但我想支持多个参数。
(反射可以实现,但是不想用反射)
只基于 generic 还能进一步抽象支持多参数不?
package cache
import (
"sync"
"testing"
)
type CacheFn[K comparable, V any] struct {
redisMap sync.Map
routineOnceMap sync.Map
getFunc func(K) V
}
func NewCacheFn[K comparable, V any](getFunc func(K) V) *CacheFn[K, V] {
return &CacheFn[K, V]{getFunc: getFunc}
}
// 1. 执行缓存到 redisMap 或其它存储; 2.如果多个协程同时执行时,只执行一次(其它协程被阻塞)
func (c *CacheFn[K, V]) Get(key K) V {
value, ok := c.redisMap.Load(key)
if ok {
return value.(V)
} else {
var once sync.Once
onceInterface, loaded := c.routineOnceMap.LoadOrStore(key, &once)
if loaded { // 如果有其它协程在执行,则等待它结束
oncePtr := onceInterface.(*sync.Once)
oncePtr.Do(func() {})
} else { // 第一次访问,进行 DB 查询
once.Do(func() {
value = c.getFunc(key)
c.redisMap.Store(key, value)
})
}
val, _ := c.redisMap.Load(key)
return val.(V)
}
}
func TestCacheFuncWrapperGeneric(t *testing.T) {
type UserInfo struct {
Name string
Age int
}
// 原始函数
getUserInfoFromDb := func(name string) UserInfo {
println("get info from db:", name)
return UserInfo{Name: name}
}
// 带缓存的函数
getUserInfoFromDbWithCache := NewCacheFn(getUserInfoFromDb) // getFunc 只接受一个参数,怎么接收多个参数呢?
// 多个协程同时执行
batchCall := func(t *testing.T, fn func()) {
var wg sync.WaitGroup
for k := 0; k < 10; k++ {
wg.Add(1)
go func(i int) {
fn()
wg.Done()
}(k)
}
wg.Wait()
}
// 多次调用函数, 只执行一次
batchCall(t, func() {
userinfo := getUserInfoFromDbWithCache.Get("alex")
t.Log(userinfo)
})
}
1
sora2blue 2023-07-29 00:58:21 +08:00
你可以把参数列表从`func(K) V`改成`func(...any) V`,参考`fmt.Printf`,不过这种办法需要自己取出参数做类型声明
如果你是想要直接传任意长度的带类型声明的参数列表,不如直接传一个结构体进去,结构体里面存参数,结构体的类型作为泛型声明的一部分 |
2
MAKF 2023-07-29 10:31:44 +08:00
...argc, 当成 array 用
|
3
a132811 OP |
4
Anubisks 2023-07-31 07:09:07 +08:00
结构体吧
|