dc80b557e3
2020/12/16: 添加YAML和结构体转换工具
173 lines
3.6 KiB
Go
173 lines
3.6 KiB
Go
package linq
|
|
|
|
import "reflect"
|
|
|
|
// Iterator is an alias for function to iterate over data.
|
|
type Iterator func() (item interface{}, ok bool)
|
|
|
|
// Query is the type returned from query functions. It can be iterated manually
|
|
// as shown in the example.
|
|
type Query struct {
|
|
Iterate func() Iterator
|
|
}
|
|
|
|
// KeyValue is a type that is used to iterate over a map (if query is created
|
|
// from a map). This type is also used by ToMap() method to output result of a
|
|
// query into a map.
|
|
type KeyValue struct {
|
|
Key interface{}
|
|
Value interface{}
|
|
}
|
|
|
|
// Iterable is an interface that has to be implemented by a custom collection in
|
|
// order to work with linq.
|
|
type Iterable interface {
|
|
Iterate() Iterator
|
|
}
|
|
|
|
// From initializes a linq query with passed slice, array or map as the source.
|
|
// String, channel or struct implementing Iterable interface can be used as an
|
|
// input. In this case From delegates it to FromString, FromChannel and
|
|
// FromIterable internally.
|
|
func From(source interface{}) Query {
|
|
src := reflect.ValueOf(source)
|
|
|
|
switch src.Kind() {
|
|
case reflect.Slice, reflect.Array:
|
|
len := src.Len()
|
|
|
|
return Query{
|
|
Iterate: func() Iterator {
|
|
index := 0
|
|
|
|
return func() (item interface{}, ok bool) {
|
|
ok = index < len
|
|
if ok {
|
|
item = src.Index(index).Interface()
|
|
index++
|
|
}
|
|
|
|
return
|
|
}
|
|
},
|
|
}
|
|
case reflect.Map:
|
|
len := src.Len()
|
|
|
|
return Query{
|
|
Iterate: func() Iterator {
|
|
index := 0
|
|
keys := src.MapKeys()
|
|
|
|
return func() (item interface{}, ok bool) {
|
|
ok = index < len
|
|
if ok {
|
|
key := keys[index]
|
|
item = KeyValue{
|
|
Key: key.Interface(),
|
|
Value: src.MapIndex(key).Interface(),
|
|
}
|
|
|
|
index++
|
|
}
|
|
|
|
return
|
|
}
|
|
},
|
|
}
|
|
case reflect.String:
|
|
return FromString(source.(string))
|
|
case reflect.Chan:
|
|
return FromChannel(source.(chan interface{}))
|
|
default:
|
|
return FromIterable(source.(Iterable))
|
|
}
|
|
}
|
|
|
|
// FromChannel initializes a linq query with passed channel, linq iterates over
|
|
// channel until it is closed.
|
|
func FromChannel(source <-chan interface{}) Query {
|
|
return Query{
|
|
Iterate: func() Iterator {
|
|
return func() (item interface{}, ok bool) {
|
|
item, ok = <-source
|
|
return
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
// FromString initializes a linq query with passed string, linq iterates over
|
|
// runes of string.
|
|
func FromString(source string) Query {
|
|
runes := []rune(source)
|
|
len := len(runes)
|
|
|
|
return Query{
|
|
Iterate: func() Iterator {
|
|
index := 0
|
|
|
|
return func() (item interface{}, ok bool) {
|
|
ok = index < len
|
|
if ok {
|
|
item = runes[index]
|
|
index++
|
|
}
|
|
|
|
return
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
// FromIterable initializes a linq query with custom collection passed. This
|
|
// collection has to implement Iterable interface, linq iterates over items,
|
|
// that has to implement Comparable interface or be basic types.
|
|
func FromIterable(source Iterable) Query {
|
|
return Query{
|
|
Iterate: source.Iterate,
|
|
}
|
|
}
|
|
|
|
// Range generates a sequence of integral numbers within a specified range.
|
|
func Range(start, count int) Query {
|
|
return Query{
|
|
Iterate: func() Iterator {
|
|
index := 0
|
|
current := start
|
|
|
|
return func() (item interface{}, ok bool) {
|
|
if index >= count {
|
|
return nil, false
|
|
}
|
|
|
|
item, ok = current, true
|
|
|
|
index++
|
|
current++
|
|
return
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
// Repeat generates a sequence that contains one repeated value.
|
|
func Repeat(value interface{}, count int) Query {
|
|
return Query{
|
|
Iterate: func() Iterator {
|
|
index := 0
|
|
|
|
return func() (item interface{}, ok bool) {
|
|
if index >= count {
|
|
return nil, false
|
|
}
|
|
|
|
item, ok = value, true
|
|
|
|
index++
|
|
return
|
|
}
|
|
},
|
|
}
|
|
}
|