| // run | |
| // Copyright 2021 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package main | |
| import ( | |
| "fmt" | |
| ) | |
| type AnyCacher[T any] interface { | |
| // Get an item from the cache. Returns the item or nil, and a bool indicating | |
| // whether the key was found. | |
| Get(k string) (T, bool) | |
| // Add an item to the cache, replacing any existing item. | |
| Set(k string, x T) | |
| } | |
| // Item ... | |
| type Item[T any] struct { | |
| Object T | |
| } | |
| // AnyCache implements AnyCacher | |
| type AnyCache[T any] struct { | |
| *anyCache[T] | |
| } | |
| type anyCache[T any] struct { | |
| items map[string]Item[T] | |
| janitor *janitor[T] // Needed for the failure in the issue | |
| } | |
| // Set adds an item to the cache, replacing any existing item. | |
| func (c *anyCache[T]) Set(k string, x T) { | |
| c.items[k] = Item[T]{ | |
| Object: x, | |
| } | |
| } | |
| // Get gets an item from the cache. Returns the item or nil, and a bool indicating | |
| // whether the key was found. | |
| func (c *anyCache[T]) Get(k string) (T, bool) { | |
| // "Inlining" of get and Expired | |
| item, found := c.items[k] | |
| if !found { | |
| var ret T | |
| return ret, false | |
| } | |
| return item.Object, true | |
| } | |
| type janitor[T any] struct { | |
| stop chan bool | |
| } | |
| func newAnyCache[T any](m map[string]Item[T]) *anyCache[T] { | |
| c := &anyCache[T]{ | |
| items: m, | |
| } | |
| return c | |
| } | |
| // NewAny[T any](...) returns a new AnyCache[T]. | |
| func NewAny[T any]() *AnyCache[T] { | |
| items := make(map[string]Item[T]) | |
| return &AnyCache[T]{newAnyCache(items)} | |
| } | |
| // NewAnyCacher[T any](...) returns an AnyCacher[T] interface. | |
| func NewAnyCacher[T any]() AnyCacher[T] { | |
| return NewAny[T]() | |
| } | |
| type MyStruct struct { | |
| Name string | |
| } | |
| func main() { | |
| // Create a generic cache. | |
| // All items are cached as interface{} so they need to be cast back to their | |
| // original type when retrieved. | |
| // Failure in issue doesn't happen with 'any' replaced by 'interface{}' | |
| c := NewAnyCacher[any]() | |
| myStruct := &MyStruct{"MySuperStruct"} | |
| c.Set("MySuperStruct", myStruct) | |
| myRawCachedStruct, found := c.Get("MySuperStruct") | |
| if found { | |
| // Casting the retrieved object back to its original type | |
| myCachedStruct := myRawCachedStruct.(*MyStruct) | |
| fmt.Printf("%s", myCachedStruct.Name) | |
| } else { | |
| fmt.Printf("Error: MySuperStruct not found in cache") | |
| } | |
| // Output: | |
| // MySuperStruct | |
| } |