问题内容 我正在尝试找出在 golang 中为泛型变量实现单例的最不糟糕的方法。使用普通的 sync.once 模式与全局变量是行不通的,因为通用类型信息在那里不可用(如下)。 这个示
我正在尝试找出在 golang 中为泛型变量实现单例的最不糟糕的方法。使用普通的 sync.once
模式与全局变量是行不通的,因为通用类型信息在那里不可用(如下)。
这个示例是人为设计的,但实际上,维护单例的代码可以与定义 t
的客户端代码分开(例如在库中)。
假设此库代码,其中 t 的具体值未知:
type cache[t any] struct{}
var (
cacheonce sync.once
cache cache[any] // global singleton
)
func getorcreatecache[t any]() cache[t] {
cacheonce.do(func() {
typedcache := buildcache()
cache = typedcache.(cache[any]) // invalid type assertion
})
return cache.(cache[t]) // invalid type assertion
}
并假设这个单独的客户端代码,其中 t
被定义为 string
:
strinGCache := getOrCreateCache[string]()
实现这一目标的最佳方法是什么?
我最终使用 atomic.pointer
api 解决了这个问题,并将其整合到一个简单的库中,供其他感兴趣的人使用:单线。使用单线态重新处理原始帖子如下所示:
示例库代码:
type cache[t any] struct{}
var singleton = &singlet.singleton{}
func getorcreatecache[t any]() (cache[t], err) {
return singlet.getordo(singleton, func() cache[t] {
return cache[t]{}
})
}
客户端代码:
stringcache := getorcreatecache[string]()
以及支持此功能的 singlet 库代码:
var ErrTypeMismatch = errors.New("the requested type does not match the singleton type")
type Singleton struct {
p atomic.Pointer[any]
mtx sync.Mutex
}
func GetOrDo[T any](singleton *Singleton, fn func() T) (result T, err error) {
maybeResult := singleton.p.Load()
if maybeResult == nil {
// Lock to guard against applying fn twice
singleton.mtx.Lock()
defer singleton.mtx.Unlock()
maybeResult = singleton.p.Load()
// Double check
if maybeResult == nil {
result = fn()
var resultAny any = result
singleton.p.Store(&resultAny)
return result, nil
}
}
var ok bool
result, ok = (*maybeResult).(T)
if !ok {
return *new(T), ErrTypeMismatch
}
return result, nil
}
我希望对遇到这种情况的其他人有所帮助。
--结束END--
本文标题: 带有 Go 泛型的单例模式
本文链接: https://lsjlt.com/news/561188.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0