...

Source file src/github.com/thoas/go-funk/retrieve.go

Documentation: github.com/thoas/go-funk

     1  package funk
     2  
     3  import (
     4  	"reflect"
     5  	"strings"
     6  )
     7  
     8  // Get retrieves the value from given path, retriever can be modified with available RetrieverOptions
     9  func Get(out interface{}, path string, opts ...option) interface{} {
    10  	options := newOptions(opts...)
    11  
    12  	result := get(reflect.ValueOf(out), path)
    13  	// valid kind and we can return a result.Interface() without panic
    14  	if result.Kind() != reflect.Invalid && result.CanInterface() {
    15  		// if we don't allow zero and the result is a zero value return nil
    16  		if !options.allowZero && result.IsZero() {
    17  			return nil
    18  		}
    19  		// if the result kind is a pointer and its nil return nil
    20  		if result.Kind() == reflect.Ptr && result.IsNil() {
    21  			return nil
    22  		}
    23  		// return the result interface (i.e the zero value of it)
    24  		return result.Interface()
    25  	}
    26  
    27  	return nil
    28  }
    29  
    30  // GetOrElse retrieves the value of the pointer or default.
    31  func GetOrElse(v interface{}, def interface{}) interface{} {
    32  	val := reflect.ValueOf(v)
    33  	if v == nil || (val.Kind() == reflect.Ptr && val.IsNil()) {
    34  		return def
    35  	} else if val.Kind() != reflect.Ptr {
    36  		return v
    37  	}
    38  	return val.Elem().Interface()
    39  }
    40  
    41  func get(value reflect.Value, path string) reflect.Value {
    42  	if value.Kind() == reflect.Slice || value.Kind() == reflect.Array {
    43  		var resultSlice reflect.Value
    44  
    45  		length := value.Len()
    46  
    47  		if length == 0 {
    48  			zeroElement := reflect.Zero(value.Type().Elem())
    49  			pathValue := get(zeroElement, path)
    50  			value = reflect.MakeSlice(reflect.SliceOf(pathValue.Type()), 0, 0)
    51  
    52  			return value
    53  		}
    54  
    55  		for i := 0; i < length; i++ {
    56  			item := value.Index(i)
    57  
    58  			resultValue := get(item, path)
    59  
    60  			if resultValue.Kind() == reflect.Invalid || resultValue.IsZero() {
    61  				continue
    62  			}
    63  
    64  			resultType := resultValue.Type()
    65  
    66  			if resultSlice.Kind() == reflect.Invalid {
    67  				resultType := reflect.SliceOf(resultType)
    68  
    69  				resultSlice = reflect.MakeSlice(resultType, 0, 0)
    70  			}
    71  
    72  			resultSlice = reflect.Append(resultSlice, resultValue)
    73  		}
    74  
    75  		// if the result is a slice of a slice, we need to flatten it
    76  		if resultSlice.Kind() != reflect.Invalid && resultSlice.Type().Elem().Kind() == reflect.Slice {
    77  			return flattenDeep(resultSlice)
    78  		}
    79  
    80  		return resultSlice
    81  	}
    82  
    83  	parts := strings.Split(path, ".")
    84  
    85  	for _, part := range parts {
    86  		value = redirectValue(value)
    87  		kind := value.Kind()
    88  
    89  		switch kind {
    90  		case reflect.Invalid:
    91  			continue
    92  		case reflect.Struct:
    93  			value = value.FieldByName(part)
    94  		case reflect.Map:
    95  			value = value.MapIndex(reflect.ValueOf(part))
    96  		case reflect.Slice, reflect.Array:
    97  			value = get(value, part)
    98  		default:
    99  			return reflect.ValueOf(nil)
   100  		}
   101  	}
   102  
   103  	return value
   104  }
   105  

View as plain text