问题内容
我正在尝试找出在 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}
登录后复制
我希望对遇到这种情况的其他人有所帮助。
以上就是带有 Go 泛型的单例模式的详细内容,更多请关注【创想鸟】其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。
发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2360586.html