func GetStringList(config map[string]interface{}, field string, opts ...Option) ([]string, error) {
	options := getOptions(opts...)
	out, err := GetInterfaceList(config, field)
	if err != nil {
		if options.withDefault && errors.Cause(err) == ErrNotFound {
			return options.defaultValue.([]string), nil
		}
		return nil, errors.Wrapf(err, "couldn't get []interface{}")
	}
	var outStrings []string
	for i := range out {
		outString, ok := out[i].(string)
		if !ok {
			return nil, errors.Errorf("expected string slice, got %v at index %v", reflect.TypeOf(out[i]), i)
		}
		outStrings = append(outStrings, outString)
	}
	return outStrings, nil
}
GetStringList gets a string list from the given field.
package config
import (
	"reflect"
	"strconv"
	"strings"
	"github.com/pkg/errors"
)
var ErrNotFound = errors.New("field not found")
type Option func(options *options)
type options struct {
	withDefault  bool
	defaultValue interface{}
}
func getOptions(opts ...Option) *options {
	defaultOptions := &options{
		withDefault:  false,
		defaultValue: nil,
	}
	for _, opt := range opts {
		opt(defaultOptions)
	}
	return defaultOptions
}
func WithDefault(value interface{}) Option {
	return func(options *options) {
		options.withDefault = true
		options.defaultValue = value
	}
}
func GetInterface(config map[string]interface{}, field string, opts ...Option) (interface{}, error) {
	options := getOptions(opts...)
	i := strings.Index(field, ".")
	if i == -1 {
		element, ok := config[field]
		if options.withDefault && !ok {
			return options.defaultValue, nil
		}
		if !ok {
			return nil, ErrNotFound
		}
		return element, nil
	}
	element, ok := config[field[:i]]
	if options.withDefault && !ok {
		return options.defaultValue, nil
	}
	if !ok {
		return nil, ErrNotFound
	}
	submap, ok := element.(map[string]interface{})
	if !ok {
		return nil, errors.Errorf("%v should be a map, got: %v", field[:i], reflect.TypeOf(element))
	}
	out, err := GetInterface(submap, field[i+1:])
	if err != nil {
		return nil, errors.Wrapf(err, "couldn't get interface from %v", field[i+1:])
	}
	return out, nil
}
func GetInterfaceList(config map[string]interface{}, field string, opts ...Option) ([]interface{}, error) {
	options := getOptions(opts...)
	out, err := GetInterface(config, field)
	if err != nil {
		if options.withDefault && errors.Cause(err) == ErrNotFound {
			return options.defaultValue.([]interface{}), nil
		}
		return nil, errors.Wrapf(err, "couldn't get interface{}")
	}
	if out == nil {
		return nil, nil
	}
	outTable, ok := out.([]interface{})
	if !ok {
		return nil, errors.Errorf("expected interface{} slice, got %v", reflect.TypeOf(out))
	}
	return outTable, nil
}
func GetMap(config map[string]interface{}, field string, opts ...Option) (map[string]interface{}, error) {
	options := getOptions(opts...)
	out, err := GetInterface(config, field)
	if err != nil {
		if options.withDefault && errors.Cause(err) == ErrNotFound {
			return options.defaultValue.(map[string]interface{}), nil
		}
		return nil, errors.Wrapf(err, "couldn't get interface{}")
	}
	outMap, ok := out.(map[string]interface{})
	if !ok {
		return nil, errors.Errorf("expected map, got %v", reflect.TypeOf(out))
	}
	return outMap, nil
}
func GetString(config map[string]interface{}, field string, opts ...Option) (string, error) {
	options := getOptions(opts...)
	out, err := GetInterface(config, field)
	if err != nil {
		if options.withDefault && errors.Cause(err) == ErrNotFound {
			return options.defaultValue.(string), nil
		}
		return "", errors.Wrapf(err, "couldn't get interface{}")
	}
	outString, ok := out.(string)
	if !ok {
		return "", errors.Errorf("expected string, got %v", reflect.TypeOf(out))
	}
	return outString, nil
}