Стоян обнови решението на 18.11.2014 16:49 (преди над 3 години)
+package main
+
+import "time"
+import "strconv"
+import "strings"
+
+type ExpireMap struct {
+        items         map[string]*Item
+        expireChannel chan string
+}
+
+//Връща указател към нов обект от тип ExpireMap, готов за използване.
+func NewExpireMap() *ExpireMap {
+        em := new(ExpireMap)
+        em.items = make(map[string]*Item)
+        em.expireChannel = make(chan string)
+        return em
+}
+
+//Добавя в хранилището нов ключ key със стойност value за expire време.
+//Duration е дефиниран в пакета time.
+//expire време след добавянето на ключа той вече трябва да спре да бъде в хранилището.
+//Стойността може да е от всякакъв тип, докато ключа е от тип string.
+func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
+        item := new(Item)
+        //item.key = key
+        item.value = value
+        item.expires = expire
+        item.timeAdded = time.Now()
+        em.items[key] = item
+
+        go func(key string, value interface{}, expire time.Duration) {
+                time.Sleep(expire)
+
+                if item.expires <= time.Since(item.timeAdded) {
+                        delete(em.items, key)
+                        em.expireChannel <- key
+                }
+
+        }(key, value, expire)
+
+}
+
+//Връща стойността на ключ и true, когато ключа е намерен. Когато ключа липсва или е изтекъл връща nil и false.
+func (em *ExpireMap) Get(key string) (interface{}, bool) {
+        if item, ok := em.items[key]; ok {
+                return item.value, true
+        }
+
+        return nil, false
+
+}
+
+//Връща стойността, отговаряща на този ключ и true, когато ключа е намерен и стойността му е от тип int.
+//Когато ключа липсва, изтекъл е или стойността му не е от този тип метода трябва да върне нула и false.
+func (em *ExpireMap) GetInt(key string) (int, bool) {
+        if value, ok := em.Get(key); ok {
+                if val, ok := value.(int); ok {
+                        return val, true
+                }
+
+                return 0, false
+        }
+
+        return 0, false
+}
+
+//Връща стойността на този ключ и true, когато ключа е намерен и стойността му е от тип float64.
+//Когато ключа липсва, изтекъл е или стойността му не е от този тип метода трябва да върне нула и false.
+func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
+        if value, ok := em.Get(key); ok {
+                if val, ok := value.(float64); ok {
+                        return val, true
+                }
+
+                return 0, false
+        }
+
+        return 0, false
+}
+
+//Връща стойността на ключ и true, когато ключа е намерен и стойността му е от тип string.
+//Когато ключа липсва, изтекъл е или стойността не е от тип string метода трябва да върне празен стринг и false.
+func (em *ExpireMap) GetString(key string) (string, bool) {
+        if value, ok := em.Get(key); ok {
+                if val, ok := value.(string); ok {
+                        return val, true
+                }
+
+                return "", false
+        }
+
+        return "", false
+}
+
+//Връща стойността на ключ и true, когато ключа е намерен и стойността му е от тип bool.
+//Когато ключа липсва, изтекъл е или стойността не е от тип bool метода трябва да върне false и false.
+func (em *ExpireMap) GetBool(key string) (bool, bool) {
+        if value, ok := em.Get(key); ok {
+                if val, ok := value.(bool); ok {
+                        return val, true
+                }
+
+                return false, false
+        }
+
+        return false, false
+
+}
+
+//За определен ключ тази функция трябва да върне времето, когато той ще изтече.
+//Втората върната стойност е true когато ключа е намерен в хранилището. Когато не е намерен функцията трябва да върне нулевото време и false.
+func (em *ExpireMap) Expires(key string) (time.Time, bool) {
+        item, ok := em.items[key]
+        if ok {
+                return item.timeAdded.Add(item.expires), true
+        }
+
+        return time.Time{}, false
+}
+
+//Връща големината на хранилището. Големина е бройката неизтекли ключове, които са в него.
+func (em *ExpireMap) Size() int {
+        //lock ?
+        size := 0
+        for _, item := range em.items {
+                if item.expires >= time.Since(item.timeAdded) {
+                        size++
+                }
+        }
+
+        return size
+}
+
+//Казва дали ключ е в хранилището или не. Отново, ключове са в хранилището само ако техния expire не е вече изтекъл.
+func (em *ExpireMap) Contains(key string) bool {
+        //lock
+        item, ok := em.items[key]
+
+        if ok && item.expires >= time.Since(item.timeAdded) {
+                return true
+        }
+
+        return false
+}
+
+//Премахва ключа от хранилището. Когато няма такъв ключ метода не трябав да гърми.
+func (em *ExpireMap) Delete(key string) {
+        delete(em.items, key)
+}
+
+//За ключ увеличава стойността му числово с 1 когато тази стойност е от тип int или стринг, представящ цяло число.
+//Когато стойността е от тип, различен от тези неща функцията трябва да върне грешка, различна от nil.
+//float32 и float64 не са целочислен типове. Времето на изтичане на ключа не трябва да се променя.
+func (em *ExpireMap) Increment(key string) error {
+        item, ok := em.items[key]
+
+        error := new(ExpireMapError)
+        error.ErrorMessage = "Error"
+
+        if ok {
+                if val, ok := item.value.(int); ok {
+                        item.value = val + 1
+                        return nil
+                }
+
+                if val, ok := item.value.(string); ok {
+                        if n, err := strconv.Atoi(val); err == nil {
+                                item.value = n + 1
+                                return nil
+                        }
+
+                        return error
+                }
+
+                return error
+        }
+
+        return error
+}
+
+//Същото като Increment, но намалява стойността с 1 вместо да я увеличава.
+func (em *ExpireMap) Decrement(key string) error {
+        item, ok := em.items[key]
+
+        error := new(ExpireMapError)
+        error.ErrorMessage = "Error"
+
+        if ok {
+                if val, ok := item.value.(int); ok {
+                        item.value = val - 1
+                        return nil
+                }
+
+                if val, ok := item.value.(string); ok {
+                        if n, err := strconv.Atoi(val); err == nil {
+                                item.value = n - 1
+                                return nil
+                        }
+
+                        return error
+                }
+
+                return error
+        }
+
+        return error
+}
+
+//Ако стойността за ключа key е от тип string, то всички букви в този string трябва да станат главни.
+//При успех метода трябва да върне nil, а при невъзможност да изпълни задачата - грешка.
+func (em *ExpireMap) ToUpper(key string) error {
+        item, ok := em.items[key]
+
+        error := new(ExpireMapError)
+        error.ErrorMessage = "Error"
+
+        if !ok {
+                return error
+        }
+
+        if val, ok := item.value.(string); ok {
+                item.value = strings.ToUpper(val)
+        }
+
+        return error
+}
+
+func (em *ExpireMap) ToLower(key string) error {
+        item, ok := em.items[key]
+
+        error := new(ExpireMapError)
+        error.ErrorMessage = "Error"
+
+        if !ok {
+                return error
+        }
+
+        if val, ok := item.value.(string); ok {
+                item.value = strings.ToLower(val)
+        }
+
+        return error
+}
+
+//Тази функция трябва да върне канал, по който да идват ключовете, които са изтекли.
+// Те трябва да се пускат по канала в момента на изтичането си. Ключове, които са изтрити с Delete или Cleanup не трябва да се връщат по този канал.
+// Единствено тези, които са достигнали до времето си на изтичане. Не е задължително през цялото време някой да чете от върнатия канал.
+// Ключове добавени в инстанцията след извикването на ExpireChan също трябва да се пратят по канала, когато тяхното време дойде.
+func (em *ExpireMap) ExpiredChan() <-chan string {
+        return nil
+}
+
+func (em *ExpireMap) Cleanup() {
+        em.items = make(map[string]*Item)
+}
+
+func (em *ExpireMap) Destroy() {
+
+}
+
+type Item struct {
+        //key    string
+        value     interface{}
+        expires   time.Duration
+        timeAdded time.Time
+}
+
+type ExpireMapError struct {
+        ErrorMessage string
+}
+
+func (error *ExpireMapError) Error() string {
+        return error.ErrorMessage
+}
