Skip to content

Commit

Permalink
Add ForEach
Browse files Browse the repository at this point in the history
  • Loading branch information
sunfmin committed Apr 15, 2024
1 parent 40223a9 commit 4943a53
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 25 deletions.
108 changes: 84 additions & 24 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func ExampleSet_1setfield() {
Set(&p, "Gender", 1)
printJsonV(p)
fmt.Println(MustGet(&p, "Score"))
//Output:
// Output:
// {
// "Name": "Felix",
// "Score": 66.88,
Expand All @@ -77,7 +77,7 @@ func ExampleSet_2setstructproperty() {
printJsonV(p)
fmt.Println(MustGet(&p, ".Company.Phone.Number"))

//Output:
// Output:
// {
// "Name": "",
// "Score": 0,
Expand Down Expand Up @@ -112,7 +112,7 @@ func ExampleSet_3setsliceproperty() {
fmt.Println(MustGet(&p, "Departments[4].Name"))
fmt.Println(MustGet(&p, "Projects[0].Name"))

//Output:
// Output:
// {
// "Name": "",
// "Score": 0,
Expand Down Expand Up @@ -156,7 +156,7 @@ func ExampleSet_4setmapproperty() {
printJsonV(p)
fmt.Println(MustGet(&p, "Languages.zh_CN.Code"))

//Output:
// Output:
// {
// "Name": "",
// "Score": 0,
Expand Down Expand Up @@ -186,7 +186,7 @@ func ExampleSet_5setdeeper() {

printJsonV(p)
fmt.Println(MustGet(&p, "Projects[0].Members[0].Company.Phone.Number"))
//Output:
// Output:
// {
// "Name": "",
// "Score": 0,
Expand Down Expand Up @@ -232,7 +232,7 @@ func ExampleSet_6appendtoarray() {
Set(&p, "Departments[]", d)
}
printJsonV(p)
//Output:
// Output:
// {
// "Name": "",
// "Score": 0,
Expand Down Expand Up @@ -287,12 +287,12 @@ func ExampleSet_6byteandstring() {
fmt.Println(o.IntValue)
fmt.Println(o.FloatValue)
fmt.Println(o.IntValueForBytes)
//Output:
//hello
//Felix
//22
//22.88
//22
// Output:
// hello
// Felix
// 22
// 22.88
// 22

}

Expand All @@ -302,19 +302,18 @@ func ExampleSet_7notexists() {
err := Set(&p, "Whatever.Not.Exists", "911")

fmt.Println(err)
//Output:
// Output:
// no such field
}


// Get Type of a deep nested object
func ExampleSet_8gettype() {
type Variant struct {
Name string
}
type Product struct {
Variants []*Variant
ByCode map[string]*Variant
ByCode map[string]*Variant
}
type Obj struct {
MainProduct *Product
Expand All @@ -330,15 +329,76 @@ func ExampleSet_8gettype() {
fmt.Println(GetType(o, "MainProduct.ByCode"))
fmt.Println(GetType(o, "x123.ByCode"))
fmt.Println(GetType(o, "MainProduct.ByCode.abc.NotExist"))
//Output:
//string
//*reflectutils_test.Variant
//[]*reflectutils_test.Variant
//*reflectutils_test.Product
//*reflectutils_test.Variant
//map[string]*reflectutils_test.Variant
//<nil>
//<nil>
// Output:
// string
// *reflectutils_test.Variant
// []*reflectutils_test.Variant
// *reflectutils_test.Product
// *reflectutils_test.Variant
// map[string]*reflectutils_test.Variant
// <nil>
// <nil>
}

// ForEach slice with any
func ExampleForEach_9_0_normal() {
var arr = []*Language{
{"en_US", "United States"},
{"zh_CN", "China"},
}

ForEach(arr, func(v any) {
ve := v.(*Language)
fmt.Printf("%s\n", ve.Name)
})
// Output:
// United States
// China
}

// ForEach slice with correct type
func ExampleForEach_9_1_with_type() {
var arr = []*Language{
{"en_US", "United States"},
{"zh_CN", "China"},
}

ForEach(arr, func(v *Language) {
fmt.Printf("%s\n", v.Name)
})
// Output:
// United States
// China
}

// ForEach map with any
func ExampleForEach_9_2_map_with_any() {
var m = map[string]*Language{
"en_US": {"en_US", "United States"},
"zh_CN": {"zh_CN", "China"},
}

ForEach(m, func(c any, v any) {
fmt.Printf("%s: %s\n", c.(string), v.(*Language).Name)
})
// Output:
// en_US: United States
// zh_CN: China
}

// ForEach map with any
func ExampleForEach_9_3_map_with_correct_type() {
var m = map[string]*Language{
"en_US": {"en_US", "United States"},
"zh_CN": {"zh_CN", "China"},
}

ForEach(m, func(c string, v *Language) {
fmt.Printf("%s: %s\n", c, v.Name)
})
// Output:
// en_US: United States
// zh_CN: China
}

func printJsonV(v interface{}) {
Expand Down
82 changes: 82 additions & 0 deletions foreach.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package reflectutils

import (
"fmt"
"reflect"
)

func ForEach(arr interface{}, predicate interface{}) {
var (
funcValue = reflect.ValueOf(predicate)
arrValue = reflect.ValueOf(arr)
arrType = arrValue.Type()
arrKind = arrType.Kind()
funcType = funcValue.Type()
)

if IsNil(arr) {
return
}

if !(arrKind == reflect.Array || arrKind == reflect.Slice || arrKind == reflect.Map) {
panic("First parameter must be an iteratee")
}

if arrKind == reflect.Slice || arrKind == reflect.Array {
if !isFunction(predicate, 1, 0) {
panic("Second argument must be a function with one parameter")
}

arrElemType := arrValue.Type().Elem()

// Checking whether element type is convertible to function's first argument's type.
if !arrElemType.ConvertibleTo(funcType.In(0)) {
panic("Map function's argument is not compatible with type of array.")
}

for i := 0; i < arrValue.Len(); i++ {
funcValue.Call([]reflect.Value{arrValue.Index(i)})
}
return
}

if arrKind == reflect.Map {
if !isFunction(predicate, 2, 0) {
panic("Second argument must be a function with two parameters")
}

// Type checking for Map<key, value> = (key, value)
keyType := arrType.Key()
valueType := arrType.Elem()

if !keyType.ConvertibleTo(funcType.In(0)) {
panic(fmt.Sprintf("function first argument is not compatible with %s", keyType.String()))
}

if !valueType.ConvertibleTo(funcType.In(1)) {
panic(fmt.Sprintf("function second argument is not compatible with %s", valueType.String()))
}

for _, key := range arrValue.MapKeys() {
funcValue.Call([]reflect.Value{key, arrValue.MapIndex(key)})
}
return
}
}

// isFunction returns if the argument is a function.
func isFunction(in interface{}, num ...int) bool {
funcType := reflect.TypeOf(in)

result := funcType != nil && funcType.Kind() == reflect.Func

if len(num) >= 1 {
result = result && funcType.NumIn() == num[0]
}

if len(num) == 2 {
result = result && funcType.NumOut() == num[1]
}

return result
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module github.com/sunfmin/reflectutils

go 1.17
go 1.22

0 comments on commit 4943a53

Please sign in to comment.