package utility import ( "errors" "reflect" "sync" ) type Lazy interface { Value(value interface{}) (err error) } var ( TypeMismatched = errors.New("type mismatched") ) type lazy struct { lock *sync.Once fetch func() (value interface{}, err error) value interface{} done bool } func (l *lazy) Value(value interface{}) (err error) { if l.done { l.setValueTo(value) return } l.lock.Do(func() { if l.value, err = l.fetch(); err != nil { l.lock = new(sync.Once) return } else { l.setValueTo(value) l.done = true } }) return } func (l lazy) setValueTo(receiver interface{}) (err error) { rv := reflect.Indirect(reflect.ValueOf(receiver)) vv := reflect.ValueOf(l.value) if vv.Type().AssignableTo(rv.Type()) && rv.CanSet() { rv.Set(reflect.ValueOf(l.value)) } return TypeMismatched } func NewLazy(fetch func() (value interface{}, err error)) Lazy { return &lazy{ lock: new(sync.Once), fetch: fetch, } }