golang 泛型能否支持可变参数

285 天前
 a132811

以下代码中,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)
	})
}
1266 次点击
所在节点    Go 编程语言
4 条回复
sora2blue
285 天前
你可以把参数列表从`func(K) V`改成`func(...any) V`,参考`fmt.Printf`,不过这种办法需要自己取出参数做类型声明
如果你是想要直接传任意长度的带类型声明的参数列表,不如直接传一个结构体进去,结构体里面存参数,结构体的类型作为泛型声明的一部分
MAKF
284 天前
...argc, 当成 array 用
a132811
283 天前
@sora2blue 但是自己取出参数做类型声明没问题的话,就失去了对返回值的类型推了。(这也是我不想用反射+返回值断言的原因)

直接传一个结构体的话,也就限制它只能接受单参数函数了
Anubisks
282 天前
结构体吧

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/960692

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX