package cacheimport ()typeItemstruct { Object interface{} Expiration int64}// Returns true if the item has expired.func ( Item) () bool {if .Expiration == 0 {returnfalse }returntime.Now().UnixNano() > .Expiration}const (// For use with functions that take an expiration time.NoExpirationtime.Duration = -1// For use with functions that take an expiration time. Equivalent to // passing in the same expiration duration as was given to New() or // NewFrom() when the cache was created (e.g. 5 minutes.)DefaultExpirationtime.Duration = 0)typeCachestruct { *cache// If this is confusing, see the comment at the bottom of New()}type cache struct { defaultExpiration time.Duration items map[string]Item mu sync.RWMutex onEvicted func(string, interface{}) janitor *janitor}// Add an item to the cache, replacing any existing item. If the duration is 0// (DefaultExpiration), the cache's default expiration time is used. If it is -1// (NoExpiration), the item never expires.func ( *cache) ( string, interface{}, time.Duration) {// "Inlining" of setvarint64if == DefaultExpiration { = .defaultExpiration }if > 0 { = time.Now().Add().UnixNano() } .mu.Lock() .items[] = Item{Object: ,Expiration: , }// TODO: Calls to mu.Unlock are currently not deferred because defer // adds ~200 ns (as of go1.) .mu.Unlock()}func ( *cache) ( string, interface{}, time.Duration) {varint64if == DefaultExpiration { = .defaultExpiration }if > 0 { = time.Now().Add().UnixNano() } .items[] = Item{Object: ,Expiration: , }}// Add an item to the cache, replacing any existing item, using the default// expiration.func ( *cache) ( string, interface{}) { .Set(, , DefaultExpiration)}// Add an item to the cache only if an item doesn't already exist for the given// key, or if the existing item has expired. Returns an error otherwise.func ( *cache) ( string, interface{}, time.Duration) error { .mu.Lock() , := .get()if { .mu.Unlock()returnfmt.Errorf("Item %s already exists", ) } .set(, , ) .mu.Unlock()returnnil}// Set a new value for the cache key only if it already exists, and the existing// item hasn't expired. Returns an error otherwise.func ( *cache) ( string, interface{}, time.Duration) error { .mu.Lock() , := .get()if ! { .mu.Unlock()returnfmt.Errorf("Item %s doesn't exist", ) } .set(, , ) .mu.Unlock()returnnil}// Get an item from the cache. Returns the item or nil, and a bool indicating// whether the key was found.func ( *cache) ( string) (interface{}, bool) { .mu.RLock()// "Inlining" of get and Expired , := .items[]if ! { .mu.RUnlock()returnnil, false }if .Expiration > 0 {iftime.Now().UnixNano() > .Expiration { .mu.RUnlock()returnnil, false } } .mu.RUnlock()return .Object, true}// GetWithExpiration returns an item and its expiration time from the cache.// It returns the item or nil, the expiration time if one is set (if the item// never expires a zero value for time.Time is returned), and a bool indicating// whether the key was found.func ( *cache) ( string) (interface{}, time.Time, bool) { .mu.RLock()// "Inlining" of get and Expired , := .items[]if ! { .mu.RUnlock()returnnil, time.Time{}, false }if .Expiration > 0 {iftime.Now().UnixNano() > .Expiration { .mu.RUnlock()returnnil, time.Time{}, false }// Return the item and the expiration time .mu.RUnlock()return .Object, time.Unix(0, .Expiration), true }// If expiration <= 0 (i.e. no expiration time set) then return the item // and a zeroed time.Time .mu.RUnlock()return .Object, time.Time{}, true}func ( *cache) ( string) (interface{}, bool) { , := .items[]if ! {returnnil, false }// "Inlining" of Expiredif .Expiration > 0 {iftime.Now().UnixNano() > .Expiration {returnnil, false } }return .Object, true}// Increment an item of type int, int8, int16, int32, int64, uintptr, uint,// uint8, uint32, or uint64, float32 or float64 by n. Returns an error if the// item's value is not an integer, if it was not found, or if it is not// possible to increment it by n. To retrieve the incremented value, use one// of the specialized methods, e.g. IncrementInt64.func ( *cache) ( string, int64) error { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()returnfmt.Errorf("Item %s not found", ) }switch .Object.(type) {caseint: .Object = .Object.(int) + int()caseint8: .Object = .Object.(int8) + int8()caseint16: .Object = .Object.(int16) + int16()caseint32: .Object = .Object.(int32) + int32()caseint64: .Object = .Object.(int64) + caseuint: .Object = .Object.(uint) + uint()caseuintptr: .Object = .Object.(uintptr) + uintptr()caseuint8: .Object = .Object.(uint8) + uint8()caseuint16: .Object = .Object.(uint16) + uint16()caseuint32: .Object = .Object.(uint32) + uint32()caseuint64: .Object = .Object.(uint64) + uint64()casefloat32: .Object = .Object.(float32) + float32()casefloat64: .Object = .Object.(float64) + float64()default: .mu.Unlock()returnfmt.Errorf("The value for %s is not an integer", ) } .items[] = .mu.Unlock()returnnil}// Increment an item of type float32 or float64 by n. Returns an error if the// item's value is not floating point, if it was not found, or if it is not// possible to increment it by n. Pass a negative number to decrement the// value. To retrieve the incremented value, use one of the specialized methods,// e.g. IncrementFloat64.func ( *cache) ( string, float64) error { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()returnfmt.Errorf("Item %s not found", ) }switch .Object.(type) {casefloat32: .Object = .Object.(float32) + float32()casefloat64: .Object = .Object.(float64) + default: .mu.Unlock()returnfmt.Errorf("The value for %s does not have type float32 or float64", ) } .items[] = .mu.Unlock()returnnil}// Increment an item of type int by n. Returns an error if the item's value is// not an int, or if it was not found. If there is no error, the incremented// value is returned.func ( *cache) ( string, int) (int, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(int)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an int", ) } := + .Object = .items[] = .mu.Unlock()return , nil}// Increment an item of type int8 by n. Returns an error if the item's value is// not an int8, or if it was not found. If there is no error, the incremented// value is returned.func ( *cache) ( string, int8) (int8, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(int8)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an int8", ) } := + .Object = .items[] = .mu.Unlock()return , nil}// Increment an item of type int16 by n. Returns an error if the item's value is// not an int16, or if it was not found. If there is no error, the incremented// value is returned.func ( *cache) ( string, int16) (int16, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(int16)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an int16", ) } := + .Object = .items[] = .mu.Unlock()return , nil}// Increment an item of type int32 by n. Returns an error if the item's value is// not an int32, or if it was not found. If there is no error, the incremented// value is returned.func ( *cache) ( string, int32) (int32, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(int32)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an int32", ) } := + .Object = .items[] = .mu.Unlock()return , nil}// Increment an item of type int64 by n. Returns an error if the item's value is// not an int64, or if it was not found. If there is no error, the incremented// value is returned.func ( *cache) ( string, int64) (int64, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(int64)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an int64", ) } := + .Object = .items[] = .mu.Unlock()return , nil}// Increment an item of type uint by n. Returns an error if the item's value is// not an uint, or if it was not found. If there is no error, the incremented// value is returned.func ( *cache) ( string, uint) (uint, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(uint)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an uint", ) } := + .Object = .items[] = .mu.Unlock()return , nil}// Increment an item of type uintptr by n. Returns an error if the item's value// is not an uintptr, or if it was not found. If there is no error, the// incremented value is returned.func ( *cache) ( string, uintptr) (uintptr, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(uintptr)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an uintptr", ) } := + .Object = .items[] = .mu.Unlock()return , nil}// Increment an item of type uint8 by n. Returns an error if the item's value// is not an uint8, or if it was not found. If there is no error, the// incremented value is returned.func ( *cache) ( string, uint8) (uint8, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(uint8)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an uint8", ) } := + .Object = .items[] = .mu.Unlock()return , nil}// Increment an item of type uint16 by n. Returns an error if the item's value// is not an uint16, or if it was not found. If there is no error, the// incremented value is returned.func ( *cache) ( string, uint16) (uint16, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(uint16)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an uint16", ) } := + .Object = .items[] = .mu.Unlock()return , nil}// Increment an item of type uint32 by n. Returns an error if the item's value// is not an uint32, or if it was not found. If there is no error, the// incremented value is returned.func ( *cache) ( string, uint32) (uint32, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(uint32)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an uint32", ) } := + .Object = .items[] = .mu.Unlock()return , nil}// Increment an item of type uint64 by n. Returns an error if the item's value// is not an uint64, or if it was not found. If there is no error, the// incremented value is returned.func ( *cache) ( string, uint64) (uint64, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(uint64)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an uint64", ) } := + .Object = .items[] = .mu.Unlock()return , nil}// Increment an item of type float32 by n. Returns an error if the item's value// is not an float32, or if it was not found. If there is no error, the// incremented value is returned.func ( *cache) ( string, float32) (float32, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(float32)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an float32", ) } := + .Object = .items[] = .mu.Unlock()return , nil}// Increment an item of type float64 by n. Returns an error if the item's value// is not an float64, or if it was not found. If there is no error, the// incremented value is returned.func ( *cache) ( string, float64) (float64, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(float64)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an float64", ) } := + .Object = .items[] = .mu.Unlock()return , nil}// Decrement an item of type int, int8, int16, int32, int64, uintptr, uint,// uint8, uint32, or uint64, float32 or float64 by n. Returns an error if the// item's value is not an integer, if it was not found, or if it is not// possible to decrement it by n. To retrieve the decremented value, use one// of the specialized methods, e.g. DecrementInt64.func ( *cache) ( string, int64) error {// TODO: Implement Increment and Decrement more cleanly. // (Cannot do Increment(k, n*-1) for uints.) .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()returnfmt.Errorf("Item not found") }switch .Object.(type) {caseint: .Object = .Object.(int) - int()caseint8: .Object = .Object.(int8) - int8()caseint16: .Object = .Object.(int16) - int16()caseint32: .Object = .Object.(int32) - int32()caseint64: .Object = .Object.(int64) - caseuint: .Object = .Object.(uint) - uint()caseuintptr: .Object = .Object.(uintptr) - uintptr()caseuint8: .Object = .Object.(uint8) - uint8()caseuint16: .Object = .Object.(uint16) - uint16()caseuint32: .Object = .Object.(uint32) - uint32()caseuint64: .Object = .Object.(uint64) - uint64()casefloat32: .Object = .Object.(float32) - float32()casefloat64: .Object = .Object.(float64) - float64()default: .mu.Unlock()returnfmt.Errorf("The value for %s is not an integer", ) } .items[] = .mu.Unlock()returnnil}// Decrement an item of type float32 or float64 by n. Returns an error if the// item's value is not floating point, if it was not found, or if it is not// possible to decrement it by n. Pass a negative number to decrement the// value. To retrieve the decremented value, use one of the specialized methods,// e.g. DecrementFloat64.func ( *cache) ( string, float64) error { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()returnfmt.Errorf("Item %s not found", ) }switch .Object.(type) {casefloat32: .Object = .Object.(float32) - float32()casefloat64: .Object = .Object.(float64) - default: .mu.Unlock()returnfmt.Errorf("The value for %s does not have type float32 or float64", ) } .items[] = .mu.Unlock()returnnil}// Decrement an item of type int by n. Returns an error if the item's value is// not an int, or if it was not found. If there is no error, the decremented// value is returned.func ( *cache) ( string, int) (int, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(int)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an int", ) } := - .Object = .items[] = .mu.Unlock()return , nil}// Decrement an item of type int8 by n. Returns an error if the item's value is// not an int8, or if it was not found. If there is no error, the decremented// value is returned.func ( *cache) ( string, int8) (int8, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(int8)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an int8", ) } := - .Object = .items[] = .mu.Unlock()return , nil}// Decrement an item of type int16 by n. Returns an error if the item's value is// not an int16, or if it was not found. If there is no error, the decremented// value is returned.func ( *cache) ( string, int16) (int16, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(int16)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an int16", ) } := - .Object = .items[] = .mu.Unlock()return , nil}// Decrement an item of type int32 by n. Returns an error if the item's value is// not an int32, or if it was not found. If there is no error, the decremented// value is returned.func ( *cache) ( string, int32) (int32, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(int32)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an int32", ) } := - .Object = .items[] = .mu.Unlock()return , nil}// Decrement an item of type int64 by n. Returns an error if the item's value is// not an int64, or if it was not found. If there is no error, the decremented// value is returned.func ( *cache) ( string, int64) (int64, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(int64)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an int64", ) } := - .Object = .items[] = .mu.Unlock()return , nil}// Decrement an item of type uint by n. Returns an error if the item's value is// not an uint, or if it was not found. If there is no error, the decremented// value is returned.func ( *cache) ( string, uint) (uint, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(uint)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an uint", ) } := - .Object = .items[] = .mu.Unlock()return , nil}// Decrement an item of type uintptr by n. Returns an error if the item's value// is not an uintptr, or if it was not found. If there is no error, the// decremented value is returned.func ( *cache) ( string, uintptr) (uintptr, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(uintptr)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an uintptr", ) } := - .Object = .items[] = .mu.Unlock()return , nil}// Decrement an item of type uint8 by n. Returns an error if the item's value is// not an uint8, or if it was not found. If there is no error, the decremented// value is returned.func ( *cache) ( string, uint8) (uint8, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(uint8)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an uint8", ) } := - .Object = .items[] = .mu.Unlock()return , nil}// Decrement an item of type uint16 by n. Returns an error if the item's value// is not an uint16, or if it was not found. If there is no error, the// decremented value is returned.func ( *cache) ( string, uint16) (uint16, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(uint16)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an uint16", ) } := - .Object = .items[] = .mu.Unlock()return , nil}// Decrement an item of type uint32 by n. Returns an error if the item's value// is not an uint32, or if it was not found. If there is no error, the// decremented value is returned.func ( *cache) ( string, uint32) (uint32, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(uint32)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an uint32", ) } := - .Object = .items[] = .mu.Unlock()return , nil}// Decrement an item of type uint64 by n. Returns an error if the item's value// is not an uint64, or if it was not found. If there is no error, the// decremented value is returned.func ( *cache) ( string, uint64) (uint64, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(uint64)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an uint64", ) } := - .Object = .items[] = .mu.Unlock()return , nil}// Decrement an item of type float32 by n. Returns an error if the item's value// is not an float32, or if it was not found. If there is no error, the// decremented value is returned.func ( *cache) ( string, float32) (float32, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(float32)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an float32", ) } := - .Object = .items[] = .mu.Unlock()return , nil}// Decrement an item of type float64 by n. Returns an error if the item's value// is not an float64, or if it was not found. If there is no error, the// decremented value is returned.func ( *cache) ( string, float64) (float64, error) { .mu.Lock() , := .items[]if ! || .Expired() { .mu.Unlock()return0, fmt.Errorf("Item %s not found", ) } , := .Object.(float64)if ! { .mu.Unlock()return0, fmt.Errorf("The value for %s is not an float64", ) } := - .Object = .items[] = .mu.Unlock()return , nil}// Delete an item from the cache. Does nothing if the key is not in the cache.func ( *cache) ( string) { .mu.Lock() , := .delete() .mu.Unlock()if { .onEvicted(, ) }}func ( *cache) ( string) (interface{}, bool) {if .onEvicted != nil {if , := .items[]; {delete(.items, )return .Object, true } }delete(.items, )returnnil, false}type keyAndValue struct { key string value interface{}}// Delete all expired items from the cache.func ( *cache) () {var []keyAndValue := time.Now().UnixNano() .mu.Lock()for , := range .items {// "Inlining" of expiredif .Expiration > 0 && > .Expiration { , := .delete()if { = append(, keyAndValue{, }) } } } .mu.Unlock()for , := range { .onEvicted(.key, .value) }}// Sets an (optional) function that is called with the key and value when an// item is evicted from the cache. (Including when it is deleted manually, but// not when it is overwritten.) Set to nil to disable.func ( *cache) ( func(string, interface{})) { .mu.Lock() .onEvicted = .mu.Unlock()}// Write the cache's items (using Gob) to an io.Writer.//// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the// documentation for NewFrom().)func ( *cache) ( io.Writer) ( error) { := gob.NewEncoder()deferfunc() {if := recover(); != nil { = fmt.Errorf("Error registering item types with Gob library") } }() .mu.RLock()defer .mu.RUnlock()for , := range .items {gob.Register(.Object) } = .Encode(&.items)return}// Save the cache's items to the given filename, creating the file if it// doesn't exist, and overwriting it if it does.//// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the// documentation for NewFrom().)func ( *cache) ( string) error { , := os.Create()if != nil {return } = .Save()if != nil { .Close()return }return .Close()}// Add (Gob-serialized) cache items from an io.Reader, excluding any items with// keys that already exist (and haven't expired) in the current cache.//// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the// documentation for NewFrom().)func ( *cache) ( io.Reader) error { := gob.NewDecoder() := map[string]Item{} := .Decode(&)if == nil { .mu.Lock()defer .mu.Unlock()for , := range { , := .items[]if ! || .Expired() { .items[] = } } }return}// Load and add cache items from the given filename, excluding any items with// keys that already exist in the current cache.//// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the// documentation for NewFrom().)func ( *cache) ( string) error { , := os.Open()if != nil {return } = .Load()if != nil { .Close()return }return .Close()}// Copies all unexpired items in the cache into a new map and returns it.func ( *cache) () map[string]Item { .mu.RLock()defer .mu.RUnlock() := make(map[string]Item, len(.items)) := time.Now().UnixNano()for , := range .items {// "Inlining" of Expiredif .Expiration > 0 {if > .Expiration {continue } } [] = }return}// Returns the number of items in the cache. This may include items that have// expired, but have not yet been cleaned up.func ( *cache) () int { .mu.RLock() := len(.items) .mu.RUnlock()return}// Delete all items from the cache.func ( *cache) () { .mu.Lock() .items = map[string]Item{} .mu.Unlock()}type janitor struct { Interval time.Duration stop chanbool}func ( *janitor) ( *cache) { := time.NewTicker(.Interval)for {select {case<-.C: .DeleteExpired()case<-.stop: .Stop()return } }}func stopJanitor( *Cache) { .janitor.stop <- true}func runJanitor( *cache, time.Duration) { := &janitor{Interval: ,stop: make(chanbool), } .janitor = go .Run()}func newCache( time.Duration, map[string]Item) *cache {if == 0 { = -1 } := &cache{defaultExpiration: ,items: , }return}func newCacheWithJanitor( time.Duration, time.Duration, map[string]Item) *Cache { := newCache(, )// This trick ensures that the janitor goroutine (which--granted it // was enabled--is running DeleteExpired on c forever) does not keep // the returned C object from being garbage collected. When it is // garbage collected, the finalizer stops the janitor goroutine, after // which c can be collected. := &Cache{}if > 0 {runJanitor(, )runtime.SetFinalizer(, stopJanitor) }return}// Return a new cache with a given default expiration duration and cleanup// interval. If the expiration duration is less than one (or NoExpiration),// the items in the cache never expire (by default), and must be deleted// manually. If the cleanup interval is less than one, expired items are not// deleted from the cache before calling c.DeleteExpired().func (, time.Duration) *Cache { := make(map[string]Item)returnnewCacheWithJanitor(, , )}// Return a new cache with a given default expiration duration and cleanup// interval. If the expiration duration is less than one (or NoExpiration),// the items in the cache never expire (by default), and must be deleted// manually. If the cleanup interval is less than one, expired items are not// deleted from the cache before calling c.DeleteExpired().//// NewFrom() also accepts an items map which will serve as the underlying map// for the cache. This is useful for starting from a deserialized cache// (serialized using e.g. gob.Encode() on c.Items()), or passing in e.g.// make(map[string]Item, 500) to improve startup performance when the cache// is expected to reach a certain minimum size.//// Only the cache's methods synchronize access to this map, so it is not// recommended to keep any references to the map around after creating a cache.// If need be, the map can be accessed at a later point using c.Items() (subject// to the same caveat.)//// Note regarding serialization: When using e.g. gob, make sure to// gob.Register() the individual types stored in the cache before encoding a// map retrieved with c.Items(), and to register those same types before// decoding a blob containing an items map.func (, time.Duration, map[string]Item) *Cache {returnnewCacheWithJanitor(, , )}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.