Golang Go语言中泛型能否支持可变参数

发布于 1周前 作者 caililin 来自 Go语言

以下代码中,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)
})

}


Golang Go语言中泛型能否支持可变参数

更多关于Golang Go语言中泛型能否支持可变参数的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

你可以把参数列表从func(K) V改成func(...any) V,参考fmt.Printf,不过这种办法需要自己取出参数做类型声明
如果你是想要直接传任意长度的带类型声明的参数列表,不如直接传一个结构体进去,结构体里面存参数,结构体的类型作为泛型声明的一部分

更多关于Golang Go语言中泛型能否支持可变参数的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


…argc, 当成 array 用

但是自己取出参数做类型声明没问题的话,就失去了对返回值的类型推了。(这也是我不想用反射+返回值断言的原因)

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

结构体吧

在Go语言中,泛型是Go 1.18版本引入的一个重要特性,它允许开发者编写更加通用和可复用的代码。然而,关于泛型是否支持可变参数(即变长参数列表),需要明确的是,Go语言的泛型本身并不直接支持变长参数。

Go语言的变长参数是通过在函数参数类型前加上省略号(...)来实现的,例如func myFunc(args ...int)。但这种语法与泛型声明中的类型参数列表不兼容。泛型类型参数需要明确指定类型,而变长参数则允许传入任意数量的同类型参数。

尽管泛型不支持直接声明变长参数,但你可以通过其他方式实现类似的功能。例如,你可以定义一个泛型函数,该函数接受一个切片(slice)作为参数,切片本质上可以表示任意数量的元素。这样,你就可以在调用泛型函数时传入一个包含任意数量元素的切片,从而间接实现变长参数的效果。

此外,Go语言的接口(interface)也可以用来实现更加灵活的参数传递。你可以定义一个接受接口类型的泛型函数,然后在调用时传入实现了该接口的任何类型,包括切片或其他容器类型。

总之,虽然Go语言的泛型不支持直接声明变长参数,但你可以通过切片、接口等机制来实现类似的功能,从而编写出更加灵活和可复用的代码。

回到顶部