A tiny go package that helps converting values from/to a string.
var yesno bool
sb, err := strconvx.New(&yesno)
sb.FromString("true")
sb.ToString()
- string, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, complex64, complex128
time.Time
[]byte
When calling strconvx.New(x)
with an instance x
that is not a StringConverter
itself, nor any of the above builtin types, it will try to create a "hybrid" StringConverter instance from x
for you.
Here is how the "hybrid" StringConverter instance will be created:
- Create a hybrid instance
h
from the given instancex
; - If
x
has implemented one ofstrconvx.CanToString
andencoding.TextMarshaler
,h
will use it as the implementation ofstrconvx.CanToString
, i.e. theToString()
method; - If
x
has implemented one ofstrconvx.CanFromString
andencoding.TextUnmarshaler
,h
will use it as the implementation ofstrconvx.CanFromString
, i.e. theFromString()
method; - As long as
h
has an implementation of eitherstrconvx.CanToString
orstrconvx.CanFromString
, we considerh
is a validStringConverter
instance. You can require both by passing in aCompleteHybrid()
option toNew
method. For a validh
,strconvx.New(x)
will returnh
. Otherwise, anErrUnsupportedType
occurs.
Example:
type Location struct {
X int
Y int
}
func (l *Location) MarshalText() ([]byte, error) {
return []byte(fmt.Sprintf("L(%d,%d)", l.X, l.Y)), nil
}
loc := &Location{3, 4}
sb, err := strconvx.New(loc) // err is nil
sb.ToString() // L(3,4)
sb.FromString("L(5,6)") // ErrNotStringUnmarshaler, "not a CanFromString"
New(v, NoHybrid())
: preventNew
from trying to create a hybrid instance fromv
at all. Instead, returnsErrUnsupportedType
.New(v, CompleteHybrid())
: still allowNew
trying to create a hybrid instance fromv
if necessary, but with the present ofCompleteHybrid()
option, the returned hybrid instance must have a valid implementation of bothFromString
andToString
.
The Namespace.Adapt()
API is used to customize the behaviour of strconvx.StringConverter
of a specific type. The principal is to create a type alias to the target type you want to override, and implement the StringConverter
interface on the new type.
When should you use this API?
- change the conversion logic of the builtin types.
- change the conversion logic of existing types that are "hybridizable", but you don't want to change their implementations.
For example, the default support of bool
type in this package uses strconv.ParseBool
method to convert strings like "true", "TRUE", "f", "0", etc. to a bool value. If you want to support also converting "YES", "NO", "はい" to a bool value, you can implement a custom bool type and register it to a Namespace
instance:
type YesNo bool
func (yn YesNo) ToString() (string, error) {
if yn {
return "yes", nil
} else {
return "no", nil
}
}
func (yn *YesNo) FromString(s string) error {
switch strings.ToLower(s) {
case "yes":
*yn = true
case "no":
*yn = false
default:
return errors.New("invalid value")
}
return nil
}
func main() {
ns := strconvx.NewNamespace()
typ, adaptor := ToAnyStringConverterAdaptor(func(b *bool) (StringConverter, error) {
return (*YesNo)(b), nil
})
ns.Adapt(typ, adaptor)
var yesno bool = true
sb, err := ns.New(&yesno)
}