func extractFields(prefix []string, target interface{}) ([]Field, error) {
	if prefix == nil {
		prefix = []string{}
	}
	s := reflect.ValueOf(target)
	if s.Kind() != reflect.Ptr {
		return nil, ErrInvalidStruct
	}
	s = s.Elem()
	if s.Kind() != reflect.Struct {
		return nil, ErrInvalidStruct
	}
	targetType := s.Type()
	var fields []Field
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)
		structField := targetType.Field(i)
		fieldTags := structField.Tag.Get("conf")
		if !f.CanSet() || fieldTags == "-" {
			continue
		}
		fieldName := structField.Name
		fieldOpts, err := parseTag(fieldTags)
		if err != nil {
			return nil, fmt.Errorf("conf: error parsing tags for field %s: %s", fieldName, err)
		}
		fieldKey := append(prefix, camelSplit(fieldName)...)
		for f.Kind() == reflect.Ptr {
			if f.IsNil() {
				if f.Type().Elem().Kind() != reflect.Struct {
					break
				}
				f.Set(reflect.New(f.Type().Elem()))
			}
			f = f.Elem()
		}
		switch {
		case f.Kind() == reflect.Struct:
			if setterFrom(f) == nil && textUnmarshaler(f) == nil && binaryUnmarshaler(f) == nil {
				innerPrefix := fieldKey
				if structField.Anonymous {
					innerPrefix = prefix
				}
				embeddedPtr := f.Addr().Interface()
				innerFields, err := extractFields(innerPrefix, embeddedPtr)
				if err != nil {
					return nil, err
				}
				fields = append(fields, innerFields...)
			}
		default:
			envKey := fieldKey
			if fieldOpts.EnvName != "" {
				envKey = strings.Split(fieldOpts.EnvName, "_")
			}
			flagKey := fieldKey
			if fieldOpts.FlagName != "" {
				flagKey = strings.Split(fieldOpts.FlagName, "-")
			}
			fld := Field{
				Name:      fieldName,
				EnvKey:    envKey,
				FlagKey:   flagKey,
				Field:     f,
				Options:   fieldOpts,
				BoolField: f.Kind() == reflect.Bool,
			}
			fields = append(fields, fld)
		}
	}
	return fields, nil
}
extractFields uses reflection to examine the struct and generate the keys.
package conf
import (
	"encoding"
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"time"
	"unicode"
)
type FieldError struct {
	fieldName string
	typeName  string
	value     string
	err       error
}
func (err *FieldError) Error() string {
	return fmt.Sprintf("conf: error assigning to field %s: converting '%s' to type %s. details: %s", err.fieldName, err.value, err.typeName, err.err)
}
type Field struct {
	Name    string
	FlagKey []string
	EnvKey  []string
	Field   reflect.Value
	Options FieldOptions
	BoolField bool
}
type FieldOptions struct {
	Help          string
	DefaultVal    string
	EnvName       string
	FlagName      string
	ShortFlagChar rune
	Noprint       bool
	Required      bool
	Mask          bool
}