github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/cmds/core/elvish/eval/vals/iterate.go (about) 1 package vals 2 3 import ( 4 "errors" 5 6 "github.com/u-root/u-root/cmds/core/elvish/vector" 7 ) 8 9 // Iterator wraps the Iterate method. 10 type Iterator interface { 11 // Iterate calls the passed function with each value within the receiver. 12 // The iteration is aborted if the function returns false. 13 Iterate(func(v interface{}) bool) 14 } 15 16 // Iterate iterates the supplied value, and calls the supplied function in each 17 // of its elements. The function can return false to break the iteration. It is 18 // implemented for the builtin type string, and types satisfying the 19 // listIterable or Iterator interface. For these types, it always returns a nil 20 // error. For other types, it doesn't do anything and returns an error. 21 func Iterate(v interface{}, f func(interface{}) bool) error { 22 switch v := v.(type) { 23 case Iterator: 24 v.Iterate(f) 25 case string: 26 for _, r := range v { 27 b := f(string(r)) 28 if !b { 29 break 30 } 31 } 32 case listIterable: 33 for it := v.Iterator(); it.HasElem(); it.Next() { 34 if !f(it.Elem()) { 35 break 36 } 37 } 38 default: 39 return errors.New(Kind(v) + " cannot be iterated") 40 } 41 return nil 42 } 43 44 type listIterable interface { 45 Iterator() vector.Iterator 46 } 47 48 var _ listIterable = vector.Vector(nil) 49 50 // Collect collects all elements of an iterable value into a slice. 51 func Collect(it interface{}) ([]interface{}, error) { 52 var vs []interface{} 53 if len := Len(it); len >= 0 { 54 vs = make([]interface{}, 0, len) 55 } 56 err := Iterate(it, func(v interface{}) bool { 57 vs = append(vs, v) 58 return true 59 }) 60 return vs, err 61 }