/
partial.go
50 lines (45 loc) · 1.44 KB
/
partial.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package functools
import (
"errors"
"reflect"
)
// Partial will apply params (all parameters from 2nd paramter) to the passed function (first parameter).
// The function returns another function which can be called with the rest of the parameters.
func Partial(function interface{}, params ...interface{}) (ret func(...interface{}) interface{}, err error) {
defer getErr(&err)
ret = partial(function, params...)
return
}
func partial(function interface{}, params ...interface{}) (ret func(...interface{}) interface{}) {
fn := reflect.ValueOf(function)
if fn.Kind() != reflect.Func {
newErr(errors.New("The first param is not a function"), "Partial")
}
inElem := make([]reflect.Value, 0, len(params))
for _, param := range params {
inElem = append(inElem, reflect.ValueOf(param))
}
if !verifyPartialFuncType(fn, inElem) {
newErr(errors.New("The type of function and params are not matched"), "Partial")
}
partialedFunc := func(in ...interface{}) interface{} {
params := make([]reflect.Value, 0, len(in)+len(inElem))
params = append(params, inElem...)
for _, inParam := range in {
params = append(params, reflect.ValueOf(inParam))
}
return fn.Call(params[:])[0].Interface()
}
return partialedFunc
}
func verifyPartialFuncType(fn reflect.Value, in []reflect.Value) bool {
if fn.Type().NumIn() <= len(in) {
return false
}
for i := 0; i < len(in); i++ {
if fn.Type().In(i) != in[i].Type() {
return false
}
}
return true
}