-
Notifications
You must be signed in to change notification settings - Fork 0
/
partial.go
70 lines (52 loc) · 1.65 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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package functools
import (
"reflect"
"errors"
)
/*
'Partial' returns a new partial object which when called will behave like 'func'
called with the positional arguments args.
Partial(func, args...) func(args...) interface{}
PartialSafe(func, args...) (func(args...) interface{}, err)
*/
func partial(function interface{}, args ...interface{}) func(...interface{}) interface{} {
fn := reflect.ValueOf(function)
if fn.Kind() != reflect.Func {
raise(errors.New("The first param should be a function"), "Partial")
}
reflectedArgs := make([]reflect.Value, 0, len(args))
for _, arg := range args {
reflectedArgs = append(reflectedArgs, reflect.ValueOf(arg))
}
if !verifyPartialFuncType(fn, reflectedArgs) {
raise(errors.New("The types of function and params aren't matched"), "Partial")
}
partialedFunc := func(in ...interface{}) interface{} {
params := make([]reflect.Value, 0, len(in) + len(reflectedArgs))
params = append(params, reflectedArgs...)
for _, v := range in {
params = append(params, reflect.ValueOf(v))
}
return fn.Call(params[:])[0].Interface()
}
return partialedFunc
}
func verifyPartialFuncType(fn reflect.Value, args []reflect.Value) bool {
if fn.Type().NumIn() <= len(args) {
return false
}
for i := 0; i < len(args); i++ {
if fn.Type().In(i) != args[i].Type() {
return false
}
}
return true
}
func Partial(function interface{}, args ...interface{}) func(...interface{}) interface{} {
return partial(function, args...)
}
func PartialSafe(function interface{}, args ...interface{}) (result func(...interface{}) interface{}, err error) {
defer except(&err)
result = partial(function, args...)
return
}