func (a *AttributeList) ForEach(fn func(string, interface{})) {
	a.Range(func(s string, v interface{}) bool {
		if v != nil {
			fn(s, v)
		}
		return false
	})
}
ForEach runs fn(key, value) for every entry in the attributes collection.
package entity
import (
	"fmt"
	"strconv"
	"sync"
	"time"
	"github.com/spkaeros/rscgo/pkg/log"
)
type entry struct {
	key   string
	Value interface{}
}
func (e entry) String() string {
	return e.key
}
type AttributeList struct {
	set  map[string]interface{}
	lock sync.RWMutex
}
func NewAttributeList() *AttributeList {
	return &AttributeList{set: make(map[string]interface{})}
}
func (a *AttributeList) Keys() (keys []string) {
	a.RangeK(func(k string) {
		keys = append(keys, k)
	})
	return
}
func (a *AttributeList) Values() (values []interface{}) {
	a.RangeV(func(v interface{}) {
		values = append(values, v)
	})
	return
}
func (a *AttributeList) Entries() (entries EntrySet) {
	a.ForEach(func(k string, v interface{}) {
		entries = append(entries, entry{k, v})
	})
	return
}
type EntrySet []entry
func (e EntrySet) Size() int {
	return len(e) - 1
}
func (e EntrySet) String() string {
	s := "[\n"
	for _, v := range e {
		s += "name:" + v.String() + ",value:"
		switch v.Value.(type) {
		case string:
			s += v.Value.(string) + ";\n"
		case fmt.Stringer:
			s += v.Value.(fmt.Stringer).String() + ";\n"
		case int:
			s += strconv.Itoa(v.Value.(int)) + ";\n"
		case bool:
			s += strconv.FormatBool(v.Value.(bool)) + ";\n"
		case int64:
			s += strconv.FormatInt(v.Value.(int64), 10) + ";\n"
		case float64:
			s += strconv.FormatFloat(v.Value.(float64), 'E', -1, 64) + ";\n"
		}
	}
	s += "\n]\n"
	return s
}
func (a *AttributeList) String() string {
	return a.Entries().String()
}
func (a *AttributeList) Range(fn func(string, interface{}) bool) {
	a.lock.RLock()
	defer a.lock.RUnlock()
	for k, v := range a.set {
		if fn(k, v) {
			return
		}
	}
}