goany

package module
v1.0.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 13, 2024 License: MIT Imports: 10 Imported by: 2

README

English | 中文

GoAny: A Powerful Type Conversion Library for Go

GoAny is a versatile Go lib that provides a way to convert different data types such as base types, lists, maps, structures, and more, into a specified target type. This utility uses reflection to dynamically handle type conversion, making it a flexible tool for various Go applications.

Installation

To install GoAny, use the go get command:

go get github.com/linchengzhi/goany

Example

GoAny provides the generic conversion function ToAny(in interface{}, out interface{}, options... Options) error, which can convert base types, list, map, struct, etc. It also provides a set of basic type conversion functions, such as ToInt(v interface{}) int, ToString(v interface{}) string, ToTimeE(v interface{}, op ...Options) (time.Time, error), etc. Functions ending with 'E' return an error along with the result.

func TestToAny_Example(t *testing.T) {
  var err error

  // string to int
  vint := goany.ToInt("123")
  fmt.Println(vint) //123

  vint64, err := goany.ToInt64E("123") //An E ending indicates that an error is returned
  fmt.Println(vint64, err)             //123 nil

  //nil to int, if nil, return default value
  vnil := goany.ToInt(nil)
  fmt.Println(vnil) //0

  // string to time, with options
  op := goany.NewOptions().SetLocation(time.UTC)
  vtime := goany.ToTime("2020-10-01 21:06:11", *op)
  fmt.Println(vtime) //2020-10-01 21:06:11 +0000 UTC

  // int to string
  var int1, str1 = 123, ""
  err = goany.ToAny(int1, &str1)
  fmt.Println(str1, err) //123 nil

  // time to string
  var time2, str2 = time.Date(2020, 10, 1, 21, 6, 11, 0, time.UTC), ""
  err = goany.ToAny(time2, &str2)
  fmt.Println(str2, err) //2020-10-01 21:06:11 nil
  str3, err := goany.ToStringE(time2)
  fmt.Println(str3, err) //2020-10-01 21:06:11 nil

  //map to struct
  type Person struct {
    Id   string `json:"id"`
    Name string `json:"name"`
    Age  int    `json:"age"`
  }
  var m1 = map[string]interface{}{
    "id":   1,
    "name": "John",
    "age":  20,
  }
  var p1 Person
  err = goany.ToAny(m1, &p1)
  fmt.Println(p1, err) //{1, John 20} nil
}

PS:More examples please see test.

Supported Types

GoAny supports the following conversions:

  • Basic types (integers, unsigned integers, floats, bool, string)
    Provides common conversions between base types, for example: Base types have direct conversion functions.
    v := goany.ToInt("1") //"1"
    v, err := goany.ToInt64E(123) //123 nil Functions ending with 'E' return an error along with the result.
    v := goany.ToString(1) //"1"
    
    PS:If struct(except time.Time),list,map to string, it will be converted to json. if list is []byte, it will be converted to string
  • Slices and arrays
    Provides list, map, string to list conversion, string must be json format
    var in = []interface{}{1, 2}
    var out = []string{}
    err := goany.ToAny(in, &out) //[]string{"1", "2"}
    
  • Maps
    Provides list, map, struct, string to map conversion, string must be json format
    type player struct {
        Id   int    `json:"id"`
        Name string `json:"name"`
    }
    var in = player{Id: 1, Name: "a"}
    var out = make(map[string]interface{})
    err := goany.ToAny(in, &out) //map[string]interface{}{"id": 1, "name": "a"}
    
  • Structs (including time.Time)
    Provides list, map, struct, string to struct conversion, string must be json format
    type player struct {
        Id   int    `json:"id"`
        Name string `json:"name"`
    }
    var in = map[string]interface{}{"id": 1, "name": "a"}
    var out = player{}
    err := goany.ToAny(in, &out) //player{Id: 1, Name: "a"}
    
  • Interface
    Everything can to interface.If in is struct, option structToMapDetail is true, it will be converted to map[string]interface{}
    var in = map[string]interface{}{"id": 1, "name": "a"}
    var out interface{}
    err := goany.ToAny(in, &out) //map[string]interface{}{"id": 1, "name": "a"}
    

Options

  • location
    Time zone default is "UTC".
    locationShanghai, _ := time.LoadLocation("Asia/Shanghai")
    var in = "2020-10-01 21:06:11"
    op := goany.NewOptions().SetLocation(locationShanghai)
    out, err := goany.ToTimeE(in, *op)
    fmt.Println(out, err) //2020-10-01 21:06:11 +0800 CST, nil
    
  • timeFormat
    Time format default is "2006-01-02 15:04:05"
    locationShanghai, _ := time.LoadLocation("Asia/Shanghai")
    in := time.Date(2020, 10, 1, 21, 6, 11, 0, locationShanghai)
    op := goany.NewOptions().SetLocation(locationShanghai).SetTimeFormat(time.RFC3339)
    out, err := goany.ToStringE(in, *op)
    fmt.Println(out, err)//2020-10-01T21:06:11+08:00 <nil>
    
  • mapKeyField
    When list struct to map struct, use the mapKeyField option to specify which struct field to use as the map key when converting a list of structs to a map.
    type player struct {
      Id   int    `json:"id"`
      Name string `json:"name"`
    }
    var in = []player{{Id: 1, Name: "a"}, {Id: 2, Name: "b"}}
    var out = make(map[string]player)
    op := goany.NewOptions().SetMapKeyField("name")
    err := goany.ToAny(in, &out, *op) 
    fmt.Println(out, err)//map[a:{1 a} b:{2 b}] nil
    
  • mapKeyToList
    When map is converted to list, value is converted to list by default. When mapKeyToList is true, map key is used
    var in = map[string]interface{}{"id": 1, "name": "a"}
    var out = make([]interface{}, 0)
    op := goany.NewOptions().SetMapKeyToList(true)
    err := goany.ToAny(in, &out, *op) 
    fmt.Println(out, err)//[id name] nil
    
  • tagName
    Specify the tag of the struct as the field name. The default tag is json. If there is no tag, use the field name
    type player struct {
      Id   int    `bson:"id"`
      Name string `bson:"name"`
    }
    var in = map[string]interface{}{"id": 1, "name": "a"}
    var out = player{}
    op := goany.NewOptions().SetTagName("bson")
    err := goany.ToAny(in, &out, *op) 
    fmt.Println(out, err)//player{Id: 1, Name: "a"}
    
  • exportedUnExported
    If the exportedUnExported value is true, exported fields that are not exportable in the structure can be exported. If in contains non-exportable structure fields to be exported, in must be a pointer
    type player struct {
      Id   int    `json:"id"`
      Name string `json:"name"`
      age  int    `json:"age"` //unexported
    }
    var in = map[string]interface{}{"id": 1, "name": "a", "age": 20}
    var out = player{}
    op := goany.NewOptions().SetExportedUnExported(true)
    err := goany.ToAny(in, &out, *op) 
    fmt.Println(out, err)//player{Id: 1, Name: "a", age: 20}
    
  • structToMapDetail
    When you want to convert structure depth to map, set structToMapDetail to true.If in contains non-exportable structure fields to be exported, in must be used with a use pointer
    type player struct {
      Id   int    `json:"id"`
      Name string `json:"name"`
    }
    type account struct {
      Name   string `json:"name"`
      player player `json:"player"` //nest struct
    }
    var in = account{Name: "a", player: player{Id: 1, Name: "a"}}
    var out = make(map[string]interface{})
    op := goany.NewOptions().SetStructToMapDetail(true).SetExportedUnExported(true)
    err := goany.ToAny(&in, &out, *op) // in is pointer
    fmt.Println(out, err)//map[string]interface{}{"name": "a", "player": map[string]interface{}{"id": 1, "name": "a"}}
    
  • assignKey
    When you want to convert structure to another structure, you can use assignKey to assign the field name
    type player struct {
      Id   int    `json:"id"`
      Name string `json:"name"`
    }
    type student struct {
      Sid  int    `json:"sid"` //id to sid
      Name string `json:"name"`
    }
    in := &player{Id: 1, Name: "a"}
    out := &student{}
    op := goany.NewOptions().SetAssignKey(map[string]string{"id": "sid"})
    err := goany.ToAny(in, out, *op) 
    fmt.Println(out, err)//&student{Sid: 1, Name: "a"}
    
  • hooks
    When you need to customize the parsing process, you can use hooks. The hook function is defined as: func(in interface{}, out reflect.Value) (int, error). Here, in is the input value and out is the output value. The returned integer indicates the parsing state. If the hook returns goany.DecodeContinue, the parsing continues. If it returns goany.DecodeSkip, the current value is skipped. If it returns goany.DecodeStop, it halts all parsing. Parsing also stops if the error is not nil.
    type A struct {
      Name string `json:"name"`
    }
    type B struct {
      Name string `json:"name"`
    }
    hook := func(in interface{}, out reflect.Value) (int, error) {
    inType, inVal := goany.ReflectTypeValue(in)
    if inType.Kind() == reflect.Struct {
      for i := 0; i < inType.NumField(); i++ {
        if inType.Field(i).Name == "Name" {
        inVal.Field(i).SetString(inVal.Field(i).String() + "_test")
      }
      }
    }
    return goany.DecodeContinue, nil
    }
    a := A{Name: "a"}
    b := B{}
    err := goany.ToAny(&a, &b, *goany.NewOptions().AddHook(hook))
    fmt.Println(b, err) //{a_test} <nil>
    
  • ignoreBasicTypeErr
    If the ignoreBasicTypeErr value is true, the underlying type conversion failure in the struct is skipped and the default value is used.
    type player struct {
    	Name int `json:"name"`
    	Id   int `json:"id"`
    }
    var in = map[string]interface{}{"id": 1, "name": "a"}
    var out = player{}
    op := NewOptions().SetIgnoreBasicTypeErr(true)
    err := ToAny(in, &out, *op)
    fmt.Println(out, err) //player{Id: 1, Name: 0}
    

Contributing

Contributions to improve ToAny are welcome! Please feel free to submit issues and pull requests to the repository.

License

GoAny is licensed under the MIT license. See the LICENSE file for details.

Documentation

Index

Constants

View Source
const (
	DecodeContinue = iota // continue with decoding as normal
	DecodeSkip            // skip decoding of the field
	DecodeStop            // stop decoding
)
View Source
const (
	TagIgnore = "-"
)

Variables

View Source
var (
	ErrDecodeStop           = errors.New("decode stop")
	ErrBasic                = "unable to convert %#v(type %[1]T) to "
	ErrInToOut              = "unable to convert %#v(type %[1]T) to %s"
	ErrFieldNoFound         = "the specified field was not found key: %s"
	ErrUnSupportType        = "unsupported out type %v"
	ErrUnableConvertBasic   = ErrBasic + "basic type"
	ErrUnableConvertInt64   = ErrBasic + "int64"
	ErrUnableConvertUint64  = ErrBasic + "uint64"
	ErrUnableConvertFloat64 = ErrBasic + "float64"
	ErrUnableConvertString  = ErrBasic + "string"
	ErrUnableConvertBool    = ErrBasic + "bool"
	ErrUnableConvertTime    = ErrBasic + "time"
	ErrNotJson              = "the input %#v(type %[1]T) is not json, or not map or slice"
	ErrInNotPtr             = errors.New("if want to export a unexported field, the input must be of pointer type")
)

Functions

func CheckInIsNil

func CheckInIsNil(in interface{}) bool

CheckInIsNil checks if the input is nil or if it's a nil pointer.

func GetFieldNameByTag

func GetFieldNameByTag(field reflect.StructField, tag string) string

GetFieldNameByTag returns the field name by tag. if tag is gorm, get column name if tag name is nil, get field name

func Indirect

func Indirect(a interface{}) interface{}

The Indirect function dereferences an interface{} value until it reaches a non-pointer base value or a nil value.

func ReflectTypeValue

func ReflectTypeValue(source interface{}) (reflect.Type, reflect.Value)

ReflectTypeValue returns the reflect.Type and reflect.Value of source.

func ToAny

func ToAny(in interface{}, out interface{}, options ...Options) error

ToAny converts an interface to an any type. It uses reflection to dynamically decode the input value into the output container based on the output's type.

func ToBool

func ToBool(v interface{}) bool

func ToBoolE

func ToBoolE(v interface{}, op ...Options) (bool, error)

ToBoolE convert an interface to a bool type

func ToFloat32

func ToFloat32(v interface{}) float32

ToFloat32 convert an interface to a float32 type

func ToFloat64

func ToFloat64(v interface{}) float64

ToFloat64 convert an interface to a float64 type

func ToFloat64E

func ToFloat64E(v interface{}, op ...Options) (float64, error)

func ToInt

func ToInt(v interface{}) int

func ToInt8

func ToInt8(v interface{}) int8

func ToInt16

func ToInt16(v interface{}) int16

func ToInt32

func ToInt32(v interface{}) int32

func ToInt64

func ToInt64(v interface{}) int64

ToInt64 convert an interface to an int64 type.

func ToInt64E

func ToInt64E(v interface{}, op ...Options) (int64, error)

ToInt64E is a function that attempts to convert an arbitrary type to an int64.

func ToString

func ToString(v interface{}) string

ToString convert an interface to a string type

func ToStringE

func ToStringE(v interface{}, op ...Options) (string, error)

func ToTime

func ToTime(v interface{}, op ...Options) time.Time

ToTime attempts to convert an interface value to a time.Time value

func ToTimeE

func ToTimeE(v interface{}, op ...Options) (time.Time, error)

ToTimeE attempts to convert an interface value to a time.Time value.

func ToUint

func ToUint(v interface{}) uint

func ToUint8

func ToUint8(v interface{}) uint8

func ToUint16

func ToUint16(v interface{}) uint16

func ToUint32

func ToUint32(v interface{}) uint32

func ToUint64

func ToUint64(v interface{}) uint64

func ToUint64E

func ToUint64E(v interface{}, op ...Options) (uint64, error)

Types

type HookFunc

type HookFunc func(in interface{}, out reflect.Value) (int, error)

some field can customize the parsing, such as time.Duration, net.IP, net.IPNet. return DecodeStop if the hook has handled the decoding of the field.

type IAny

type IAny interface {
	// contains filtered or unexported methods
}

IAny defines an interface for converting various types to the 'any' type.

type Options

type Options struct {
	// contains filtered or unexported fields
}

Options is a struct for specifying configuration options for any client.

func NewOptions

func NewOptions() *Options

NewOptions creates a new options. The default options are:

func (*Options) AddHook

func (op *Options) AddHook(v HookFunc) *Options

func (*Options) SetAssignKey

func (op *Options) SetAssignKey(v map[string]string) *Options

func (*Options) SetExportedUnExported

func (op *Options) SetExportedUnExported(v bool) *Options

func (*Options) SetIgnoreBasicTypeErr added in v1.0.6

func (op *Options) SetIgnoreBasicTypeErr(b bool) *Options

func (*Options) SetLocation

func (op *Options) SetLocation(v *time.Location) *Options

func (*Options) SetMapKeyField

func (op *Options) SetMapKeyField(v string) *Options

func (*Options) SetMapKeyToList

func (op *Options) SetMapKeyToList(v bool) *Options

func (*Options) SetStructToMapDetail

func (op *Options) SetStructToMapDetail(v bool) *Options

func (*Options) SetTagName

func (op *Options) SetTagName(v string) *Options

func (*Options) SetTimeFormat

func (op *Options) SetTimeFormat(v string) *Options

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL