@@ -206,6 +206,7 @@ type Viper struct {
206206 config map [string ]interface {}
207207 override map [string ]interface {}
208208 defaults map [string ]interface {}
209+ types map [string ]interface {}
209210 kvstore map [string ]interface {}
210211 pflags map [string ]FlagValue
211212 env map [string ]string
@@ -237,6 +238,7 @@ func New() *Viper {
237238 v .config = make (map [string ]interface {})
238239 v .override = make (map [string ]interface {})
239240 v .defaults = make (map [string ]interface {})
241+ v .types = make (map [string ]interface {})
240242 v .kvstore = make (map [string ]interface {})
241243 v .previousValues = make (map [string ]interface {})
242244 v .pflags = make (map [string ]FlagValue )
@@ -849,44 +851,49 @@ func (v *Viper) Get(key string) interface{} {
849851 return nil
850852 }
851853
852- if v .typeByDefValue {
853- // TODO(bep) this branch isn't covered by a single test.
854- valType := val
854+ valType := val
855855
856- v .lock .RLock ()
857- path := strings .Split (lcaseKey , v .keyDelim )
858- defVal := v .searchMap (v .defaults , path )
859- if defVal != nil {
860- valType = defVal
861- }
856+ v .lock .RLock ()
857+ path := strings .Split (lcaseKey , v .keyDelim )
858+ var valT interface {}
859+ if typeVal := v .searchMap (v .types , path ); typeVal != nil {
860+ valT = typeVal
861+ } else if v .typeByDefValue {
862+ valT = v .searchMap (v .defaults , path )
863+ } else {
864+ // no typeVal set and typeDefByValue also not set - no conversion needed
862865 v .lock .RUnlock ()
866+ return val
867+ }
868+ v .lock .RUnlock ()
863869
864- switch valType .(type ) {
865- case bool :
866- val = cast .ToBool (val )
867- case string :
868- return cast .ToString (val )
869- case int32 , int16 , int8 , int :
870- return cast .ToInt (val )
871- case uint :
872- return cast .ToUint (val )
873- case uint32 :
874- return cast .ToUint32 (val )
875- case uint64 :
876- return cast .ToUint64 (val )
877- case int64 :
878- return cast .ToInt64 (val )
879- case float64 , float32 :
880- return cast .ToFloat64 (val )
881- case time.Time :
882- return cast .ToTime (val )
883- case time.Duration :
884- return cast .ToDuration (val )
885- case []string :
886- return cast .ToStringSlice (val )
887- case []int :
888- return cast .ToIntSlice (val )
889- }
870+ valType = valT
871+
872+ switch valType .(type ) {
873+ case bool :
874+ val = cast .ToBool (val )
875+ case string :
876+ return cast .ToString (val )
877+ case int32 , int16 , int8 , int :
878+ return cast .ToInt (val )
879+ case uint :
880+ return cast .ToUint (val )
881+ case uint32 :
882+ return cast .ToUint32 (val )
883+ case uint64 :
884+ return cast .ToUint64 (val )
885+ case int64 :
886+ return cast .ToInt64 (val )
887+ case float64 , float32 :
888+ return cast .ToFloat64 (val )
889+ case time.Time :
890+ return cast .ToTime (val )
891+ case time.Duration :
892+ return cast .ToDuration (val )
893+ case []string :
894+ return cast .ToStringSlice (val )
895+ case []int :
896+ return cast .ToIntSlice (val )
890897 }
891898
892899 return val
@@ -1428,21 +1435,14 @@ func (v *Viper) InConfig(key string) bool {
14281435 return exists
14291436}
14301437
1431- // SetDefault sets the default value for this key.
1432- // SetDefault is case-insensitive for a key.
1433- // Default only used when no value is provided by the user via flag, config or ENV.
1434- func SetDefault (key string , value interface {}) { v .SetDefault (key , value ) }
1435- func (v * Viper ) SetDefault (key string , value interface {}) {
1436- // We're clearing the whole cache because nested keys may cause issues if only the key is evicted.
1437-
1438- // If alias passed in, then set the proper default
1438+ func (v * Viper ) setInMap (key string , value interface {}, target map [string ]interface {}) {
14391439 key = v .realKey (strings .ToLower (key ))
14401440 value = toCaseInsensitiveValue (value )
14411441
14421442 v .lock .RLock ()
14431443 path := strings .Split (key , v .keyDelim )
14441444 lastKey := strings .ToLower (path [len (path )- 1 ])
1445- deepestMap := deepSearch (v . defaults , path [0 :len (path )- 1 ])
1445+ deepestMap := deepSearch (target , path [0 :len (path )- 1 ])
14461446 v .lock .RUnlock ()
14471447
14481448 v .lock .Lock ()
@@ -1452,29 +1452,30 @@ func (v *Viper) SetDefault(key string, value interface{}) {
14521452 v .lock .Unlock ()
14531453}
14541454
1455+ // SetDefault sets the default value for this key.
1456+ // SetDefault is case-insensitive for a key.
1457+ // Default only used when no value is provided by the user via flag, config or ENV.
1458+ func SetDefault (key string , value interface {}) { v .SetDefault (key , value ) }
1459+ func (v * Viper ) SetDefault (key string , value interface {}) {
1460+ v .setInMap (key , value , v .defaults )
1461+ }
1462+
1463+ // SetType sets the type for this key.
1464+ // This type is used for type conversions, e.g. a slice from an env var
1465+ // This function allows the default to be nil while still enabling those type conversions configured
1466+ // through SetTypeByDefaultValue
1467+ func SetType (key string , t interface {}) { v .SetType (key , t ) }
1468+ func (v * Viper ) SetType (key string , t interface {}) {
1469+ v .setInMap (key , t , v .types )
1470+ }
1471+
14551472// Set sets the value for the key in the override register.
14561473// Set is case-insensitive for a key.
14571474// Will be used instead of values obtained via
14581475// flags, config file, ENV, default, or key/value store.
14591476func Set (key string , value interface {}) { v .Set (key , value ) }
14601477func (v * Viper ) Set (key string , value interface {}) {
1461- // We're clearing the whole cache because nested keys may cause issues if only the key is evicted.
1462-
1463- // If alias passed in, then set the proper override
1464- key = v .realKey (strings .ToLower (key ))
1465- value = toCaseInsensitiveValue (value )
1466-
1467- v .lock .RLock ()
1468- path := strings .Split (key , v .keyDelim )
1469- lastKey := strings .ToLower (path [len (path )- 1 ])
1470- deepestMap := deepSearch (v .override , path [0 :len (path )- 1 ])
1471- v .lock .RUnlock ()
1472-
1473- // set innermost value
1474- v .lock .Lock ()
1475- v .cache .Clear ()
1476- deepestMap [lastKey ] = value
1477- v .lock .Unlock ()
1478+ v .setInMap (key , value , v .override )
14781479}
14791480
14801481// ReadInConfig will discover and load the configuration file from disk
0 commit comments