mirror of
https://github.com/golang/go
synced 2024-11-14 14:30:23 -07:00
9bfe09d78b
In identical(), we don't want any to match a shape empty-interface type for the identStrict option, since IdenticalStrict() is specifically not supposed to match a shape type with a non-shape type. There is similar code in (*Type).cmp() (TINTER case), but I don't believe that we want to disqualify shape types from matching any in this case, since cmp() is used for back-end code, where we don't care about shape types vs non-shape types. The issue mainly comes about when 'any' is used as a type argument (rather than 'interface{}'), but only with some complicated circumstances, as shown by the test case. (Couldn't reproduce with simpler test cases.) Fixes #50109 Change-Id: I3f2f88be158f9ad09273237e1d346bc56aac099f Reviewed-on: https://go-review.googlesource.com/c/go/+/371154 Trust: Dan Scales <danscales@google.com> Run-TryBot: Dan Scales <danscales@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
106 lines
2.2 KiB
Go
106 lines
2.2 KiB
Go
// run -gcflags=-G=3
|
|
|
|
// 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
|
|
}
|