structs

package
v0.6.12 Latest Latest
Warning

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

Go to latest
Published: Jul 24, 2023 License: MIT Imports: 12 Imported by: 14

README

Structs

Provide some extends util functions for struct. eg: convert, tag parse, struct data init

  • structs.Aliases - implemented a simple string alias map.
  • Convert a struct to map[string]any data
  • Quickly init struct default values by field "default" tag.
  • Quickly set struct field values by map data
  • Parse a struct and collect tags, and parse tag value
  • And more util functions ...

Install

go get github.com/gookit/goutil/structs

Go docs

Usage

Convert to map

structs.ToMap() can be quickly convert a struct value to map[string]any

Examples:

	type User1 struct {
		Name string `json:"name"`
		Age  int    `json:"age"`
		city string
	}

	u1 := &User1{
		Name: "inhere",
		Age:  34,
		city: "somewhere",
	}

	mp := structs.ToMap(u1)
	dump.P(mp)

Output:

map[string]interface {} { #len=2
  "age": int(34),
  "name": string("inhere"), #len=6
},
Init default values

structs.InitDefaults Quickly init struct default value by field "default" tag.

Examples:

type Extra struct {
    City   string `default:"chengdu"`
    Github string `default:"https://github.com/inhere"`
}
type User struct {
    Name  string `default:"inhere"`
    Age   int    `default:"30"`
    Extra Extra
}

u := &User{}
_ = structs.InitDefaults(u, &structs.InitOptions{})
dump.P(u)

Output:

&structs_test.User {
  Name: string("inhere"), #len=6
  Age: int(30),
  Extra: structs_test.Extra {
    City: string("chengdu"), #len=7
    Github: string("https://github.com/inhere"), #len=25
  },
},
Set values from map
data := map[string]interface{}{
    "name": "inhere",
    "age":  234,
    "tags": []string{"php", "go"},
    "city": "chengdu",
}

type User struct {
    Name string   `json:"name"`
    Age  int      `json:"age"`
    Tags []string `json:"tags"`
    City string   `json:"city"`
}

u := &User{}
err := structs.SetValues(u, data)
dump.P(u)

Output:

&structs_test.User {
  Name: string("inhere"), #len=6
  Age: int(234),
  Tags: []string [ #len=2
    string("php"), #len=3
    string("go"), #len=2
  ],
  City: string("chengdu"), #len=7
},
Tags collect and parse

Parse a struct for collect tags, and parse tag value

Examples:

// eg: "desc;required;default;shorts"
type MyCmd struct {
    Name string `flag:"set your name;false;INHERE;n"`
}

c := &MyCmd{}
p := structs.NewTagParser("flag")

sepStr := ";"
defines := []string{"desc", "required", "default", "shorts"}
p.ValueFunc = structs.ParseTagValueDefine(sepStr, defines)

goutil.MustOK(p.Parse(c))
dump.P(p.Tags())

Output:

map[string]maputil.SMap { #len=1
  "Name": maputil.SMap { #len=1
    "flag": string("set your name;false;INHERE;n"), #len=28
  },
},

Parse tag value

info, _ := p.Info("Name", "flag")
dump.P(info)

Output:

maputil.SMap { #len=4
  "desc": string("set your name"), #len=13
  "required": string("false"), #len=5
  "default": string("INHERE"), #len=6
  "shorts": string("n"), #len=1
},

Functions API

func InitDefaults(ptr any, optFns ...InitOptFunc) error
func MustToMap(st any, optFns ...MapOptFunc) map[string]interface{}
func ParseReflectTags(rt reflect.Type, tagNames []string) (map[string]maputil.SMap, error)
func ParseTagValueDefault(field, tagVal string) (mp maputil.SMap, err error)
func ParseTagValueNamed(field, tagVal string, keys ...string) (mp maputil.SMap, err error)
func ParseTags(st any, tagNames []string) (map[string]maputil.SMap, error)
func SetValues(ptr any, data map[string]any, optFns ...SetOptFunc) error
func StructToMap(st any, optFns ...MapOptFunc) (map[string]interface{}, error)
func ToMap(st any, optFns ...MapOptFunc) map[string]interface{}
func TryToMap(st any, optFns ...MapOptFunc) (map[string]interface{}, error)
type Aliases struct{ ... }
    func NewAliases(checker func(alias string)) *Aliases
type Data struct{ ... }
    func NewData() *Data
type InitOptFunc func(opt *InitOptions)
type InitOptions struct{ ... }
type LiteData struct{ ... }
type MapOptFunc func(opt *MapOptions)
type MapOptions struct{ ... }
type SMap struct{ ... }
type SetOptFunc func(opt *SetOptions)
type SetOptions struct{ ... }
type TagParser struct{ ... }
    func NewTagParser(tagNames ...string) *TagParser
type TagValFunc func(field, tagVal string) (maputil.SMap, error)
    func ParseTagValueDefine(sep string, defines []string) TagValFunc
type Value struct{ ... }
    func NewValue(val any) *Value

Testings

go test -v ./structs/...

Test limit by regexp:

go test -v -run ^TestSetByKeys ./structs/...

Documentation

Overview

Package structs Provide some extends util functions for struct. eg: tag parse, struct init, value set

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrNotAnStruct = errors.New("must input an struct value")

ErrNotAnStruct error var emptyStringMap = make(maputil.SMap)

Functions

func ExportPrivate added in v0.6.9

func ExportPrivate(opt *MapOptions)

ExportPrivate merge anonymous struct fields to parent map

func Init added in v0.6.9

func Init(ptr any, optFns ...InitOptFunc) error

Init struct default value by field "default" tag.

func InitDefaults added in v0.5.10

func InitDefaults(ptr any, optFns ...InitOptFunc) error

InitDefaults init struct default value by field "default" tag.

TIPS:

Support init field types: string, bool, intX, uintX, floatX, array, slice

Example:

type User1 struct {
	Name string `default:"inhere"`
	Age  int32  `default:"30"`
}

u1 := &User1{}
err = structs.InitDefaults(u1)
fmt.Printf("%+v\n", u1) // Output: {Name:inhere Age:30}
Example
package main

import (
	"fmt"

	"github.com/gookit/goutil/dump"
	"github.com/gookit/goutil/structs"
)

func main() {
	type Extra struct {
		City   string `default:"chengdu"`
		Github string `default:"https://github.com/inhere"`
	}
	type User struct {
		Name  string `default:"inhere"`
		Age   int    `default:"30"`
		Extra Extra  `default:""` // add tag for init sub struct
	}

	u := &User{}
	_ = structs.InitDefaults(u)
	dump.P(u)
	/*dump:
	&structs_test.User {
	  Name: string("inhere"), #len=6
	  Age: int(30),
	  Extra: structs_test.Extra {
	    City: string("chengdu"), #len=7
	    Github: string("https://github.com/inhere"), #len=25
	  },
	},
	*/

	fmt.Println("Name:", u.Name)
	fmt.Println("Age:", u.Age)
	fmt.Println("Extra.City:", u.Extra.City)
	fmt.Println("Extra.Github:", u.Extra.Github)
}
Output:

Name: inhere
Age: 30
Extra.City: chengdu
Extra.Github: https://github.com/inhere

func IsExported added in v0.6.1

func IsExported(name string) bool

IsExported field name on struct

func IsUnexported added in v0.6.1

func IsUnexported(name string) bool

IsUnexported field name on struct

func MergeAnonymous added in v0.6.9

func MergeAnonymous(opt *MapOptions)

MergeAnonymous merge anonymous struct fields to parent map

func MustToMap added in v0.4.2

func MustToMap(st any, optFns ...MapOptFunc) map[string]any

MustToMap alis of TryToMap, but will panic on error

func MustToSMap added in v0.6.9

func MustToSMap(st any, optFns ...MapOptFunc) map[string]string

MustToSMap alias of ToStringMap(), but will panic on error

func ParseReflectTags added in v0.3.10

func ParseReflectTags(rt reflect.Type, tagNames []string) (map[string]maputil.SMap, error)

ParseReflectTags parse struct tags info.

func ParseTagValueDefault added in v0.5.10

func ParseTagValueDefault(field, tagVal string) (mp maputil.SMap, err error)

ParseTagValueDefault parse like json tag value.

see json.Marshal():

// JSON as key "myName", skipped if empty.
Field int `json:"myName,omitempty"`

// Field appears in JSON as key "Field" (the default), but skipped if empty.
Field int `json:",omitempty"`

// Field is ignored by this package.
Field int `json:"-"`

// Field appears in JSON as key "-".
Field int `json:"-,"`

Int64String int64 `json:",string"`

Returns:

{
	"name": "myName", // maybe is empty, on tag value is "-"
	"omitempty": "true",
	"string": "true",
	// ... more custom bool settings.
}

func ParseTagValueNamed added in v0.5.10

func ParseTagValueNamed(field, tagVal string, keys ...string) (mp maputil.SMap, err error)

ParseTagValueNamed parse k-v tag value string. it's like INI format contents.

Examples:

eg: "name=val0;shorts=i;required=true;desc=a message"
=>
{name: val0, shorts: i, required: true, desc: a message}

func ParseTagValueQuick added in v0.6.5

func ParseTagValueQuick(tagVal string, defines []string) maputil.SMap

ParseTagValueQuick quick parse tag value string by sep(;)

func ParseTags added in v0.3.10

func ParseTags(st any, tagNames []string) (map[string]maputil.SMap, error)

ParseTags for parse struct tags.

func SetValues added in v0.5.11

func SetValues(ptr any, data map[string]any, optFns ...SetOptFunc) error

SetValues set values to struct ptr from map data.

TIPS:

Only support set: string, bool, intX, uintX, floatX

func StructToMap added in v0.5.10

func StructToMap(st any, optFns ...MapOptFunc) (map[string]any, error)

StructToMap quickly convert structs to map[string]any by reflect. Can custom export field name by tag `json` or custom tag

func ToMap added in v0.4.2

func ToMap(st any, optFns ...MapOptFunc) map[string]any

ToMap quickly convert structs to map by reflect

Example
package main

import (
	"fmt"

	"github.com/gookit/goutil/dump"
	"github.com/gookit/goutil/structs"
)

func main() {
	type Extra struct {
		City   string `json:"city"`
		Github string `json:"github"`
	}
	type User struct {
		Name  string `json:"name"`
		Age   int    `json:"age"`
		Extra Extra  `json:"extra"`
	}

	u := &User{
		Name: "inhere",
		Age:  30,
		Extra: Extra{
			City:   "chengdu",
			Github: "https://github.com/inhere",
		},
	}

	mp := structs.ToMap(u)
	dump.P(mp)
	/*dump:
	map[string]interface {} { #len=3
	  "name": string("inhere"), #len=6
	  "age": int(30),
	  "extra": map[string]interface {} { #len=2
	    "city": string("chengdu"), #len=7
	    "github": string("https://github.com/inhere"), #len=25
	  },
	},
	*/

	fmt.Println("mp.ame:", mp["name"])
	fmt.Println("mp.age:", mp["age"])
}
Output:

mp.ame: inhere
mp.age: 30

func ToSMap added in v0.6.9

func ToSMap(st any, optFns ...MapOptFunc) map[string]string

ToSMap quickly and safe convert structs to map[string]string by reflect

func ToString added in v0.6.2

func ToString(st any, optFns ...MapOptFunc) string

ToString quickly format struct to string

func TryToMap added in v0.4.2

func TryToMap(st any, optFns ...MapOptFunc) (map[string]any, error)

TryToMap simple convert structs to map by reflect

func TryToSMap added in v0.6.9

func TryToSMap(st any, optFns ...MapOptFunc) (map[string]string, error)

TryToSMap quickly convert structs to map[string]string by reflect

func WithParseDefault added in v0.6.9

func WithParseDefault(opt *SetOptions)

WithParseDefault value by tag "default"

Types

type Aliases

type Aliases struct {

	// Checker custom add alias name checker func
	Checker func(alias string) // should return bool OR error ??
	// contains filtered or unexported fields
}

Aliases implemented a simple string alias map.

func NewAliases

func NewAliases(checker func(alias string)) *Aliases

NewAliases create

func (*Aliases) AddAlias

func (as *Aliases) AddAlias(real, alias string)

AddAlias to the Aliases

func (*Aliases) AddAliasMap

func (as *Aliases) AddAliasMap(alias2real map[string]string)

AddAliasMap to the Aliases

func (*Aliases) AddAliases

func (as *Aliases) AddAliases(real string, aliases []string)

AddAliases to the Aliases

func (*Aliases) HasAlias

func (as *Aliases) HasAlias(alias string) bool

HasAlias in the Aliases

func (*Aliases) Mapping

func (as *Aliases) Mapping() map[string]string

Mapping get all aliases mapping

func (*Aliases) ResolveAlias

func (as *Aliases) ResolveAlias(alias string) string

ResolveAlias by given name.

type Data added in v0.5.12

type Data struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

Data struct, allow enable lock

func NewData added in v0.5.12

func NewData() *Data

NewData create new data instance

func NewLiteData added in v0.6.10

func NewLiteData(data map[string]any) *Data

NewLiteData create, not locked

func (*Data) BoolVal added in v0.5.12

func (d *Data) BoolVal(key string) bool

BoolVal get from data

func (*Data) Data added in v0.5.12

func (d *Data) Data() map[string]any

Data get all

func (*Data) DataLen added in v0.5.12

func (d *Data) DataLen() int

DataLen of data

func (*Data) EnableLock added in v0.5.12

func (d *Data) EnableLock() *Data

EnableLock for operate data

func (*Data) Get added in v0.5.12

func (d *Data) Get(key string) any

Get val from data

func (*Data) GetVal added in v0.5.12

func (d *Data) GetVal(key string) any

GetVal get from data

func (*Data) IntVal added in v0.5.12

func (d *Data) IntVal(key string) int

IntVal get from data

func (*Data) Merge added in v0.6.10

func (d *Data) Merge(mp map[string]any)

Merge load new data

func (*Data) ResetData added in v0.5.12

func (d *Data) ResetData()

ResetData all data

func (*Data) Set added in v0.5.12

func (d *Data) Set(key string, val any)

Set value to data

func (*Data) SetData added in v0.5.12

func (d *Data) SetData(data map[string]any)

SetData set all data

func (*Data) SetValue added in v0.5.12

func (d *Data) SetValue(key string, val any)

SetValue to data

func (*Data) StrVal added in v0.5.12

func (d *Data) StrVal(key string) string

StrVal get from data

func (*Data) String added in v0.5.12

func (d *Data) String() string

String format data

func (*Data) Value added in v0.5.12

func (d *Data) Value(key string) (val any, ok bool)

Value get from data

func (*Data) WithLock added in v0.6.10

func (d *Data) WithLock() *Data

WithLock for operate data

type InitOptFunc added in v0.5.10

type InitOptFunc func(opt *InitOptions)

InitOptFunc define

type InitOptions added in v0.5.10

type InitOptions struct {
	// TagName default value tag name. tag: default
	TagName string
	// ParseEnv var name on default value. eg: `default:"${APP_ENV}"`
	//
	// default: false
	ParseEnv bool
	// ValueHook before set value hook TODO
	ValueHook func(val string) any
}

InitOptions struct

type LiteData added in v0.5.12

type LiteData = Data

LiteData simple map[string]any struct. no lock

type MapOptFunc added in v0.5.10

type MapOptFunc func(opt *MapOptions)

MapOptFunc define

func WithMapTagName added in v0.6.9

func WithMapTagName(tagName string) MapOptFunc

WithMapTagName set tag name for map field

type MapOptions added in v0.5.10

type MapOptions struct {
	// TagName for map filed. default is "json"
	TagName string
	// ParseDepth for parse. TODO support depth
	ParseDepth int
	// MergeAnonymous struct fields to parent map. default is true
	MergeAnonymous bool
	// ExportPrivate export private fields. default is false
	ExportPrivate bool
}

MapOptions for convert struct to map

type OrderedData added in v0.6.11

type OrderedData struct {
	maputil.Data
	// contains filtered or unexported fields
}

OrderedData data TODO

func NewOrderedData added in v0.6.11

func NewOrderedData(cap int) *OrderedData

NewOrderedData instance.

func (*OrderedData) Load added in v0.6.11

func (om *OrderedData) Load(data map[string]any)

Load data

func (*OrderedData) Set added in v0.6.11

func (om *OrderedData) Set(key string, val any)

Set key and value to map

type SMap added in v0.5.12

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

SMap simple map[string]string struct.

type SetOptFunc added in v0.5.11

type SetOptFunc func(opt *SetOptions)

SetOptFunc define

type SetOptions added in v0.5.11

type SetOptions struct {
	// FieldTagName get field name for read value. default tag: json
	FieldTagName string
	// ValueHook before set value hook TODO
	ValueHook func(val any) any

	// ParseDefault init default value by DefaultValTag tag value.
	// default: false
	//
	// see InitDefaults()
	ParseDefault bool

	// DefaultValTag name. tag: default
	DefaultValTag string

	// ParseDefaultEnv parse env var on default tag. eg: `default:"${APP_ENV}"`
	//
	// default: false
	ParseDefaultEnv bool
}

SetOptions for set values to struct

type TagParser added in v0.3.10

type TagParser struct {
	// TagNames want parsed tag names.
	TagNames []string
	// ValueFunc tag value parse func.
	ValueFunc TagValFunc
	// contains filtered or unexported fields
}

TagParser struct

func NewTagParser added in v0.5.10

func NewTagParser(tagNames ...string) *TagParser

NewTagParser instance

func (*TagParser) Info added in v0.5.10

func (p *TagParser) Info(field, tag string) (maputil.SMap, error)

Info parse the give field, returns tag value info.

info, err := p.Info("Name", "json")
exportField := info.Get("name")

func (*TagParser) Parse added in v0.5.10

func (p *TagParser) Parse(st any) error

Parse an struct value

Example
package main

import (
	"fmt"

	"github.com/gookit/goutil"
	"github.com/gookit/goutil/dump"
	"github.com/gookit/goutil/structs"
)

func main() {
	type User struct {
		Age   int    `json:"age" yaml:"age" default:"23"`
		Name  string `json:"name,omitempty" yaml:"name" default:"inhere"`
		inner string //lint:ignore U1000 for test
	}

	u := &User{}
	p := structs.NewTagParser("json", "yaml", "default")
	goutil.MustOK(p.Parse(u))

	tags := p.Tags()
	dump.P(tags)
	/*tags:
	map[string]maputil.SMap { #len=2
	  "Age": maputil.SMap { #len=3
	    "json": string("age"), #len=3
	    "yaml": string("age"), #len=3
	    "default": string("23"), #len=2
	  },
	  "Name": maputil.SMap { #len=3
	    "default": string("inhere"), #len=6
	    "json": string("name,omitempty"), #len=14
	    "yaml": string("name"), #len=4
	  },
	},
	*/

	dump.P(p.Info("name", "json"))
	/*info:
	maputil.SMap { #len=2
	  "name": string("name"), #len=4
	  "omitempty": string("true"), #len=4
	},
	*/

	fmt.Println(
		tags["Age"].Get("json"),
		tags["Age"].Get("default"),
	)

}
Output:

age 23
Example (ParseTagValueDefine)
package main

import (
	"fmt"

	"github.com/gookit/goutil"
	"github.com/gookit/goutil/dump"
	"github.com/gookit/goutil/structs"
)

func main() {
	// eg: "desc;required;default;shorts"
	type MyCmd struct {
		Name string `flag:"set your name;false;INHERE;n"`
	}

	c := &MyCmd{}
	p := structs.NewTagParser("flag")

	sepStr := ";"
	defines := []string{"desc", "required", "default", "shorts"}
	p.ValueFunc = structs.ParseTagValueDefine(sepStr, defines)

	goutil.MustOK(p.Parse(c))
	// dump.P(p.Tags())
	/*
		map[string]maputil.SMap { #len=1
		  "Name": maputil.SMap { #len=1
		    "flag": string("set your name;false;INHERE;n"), #len=28
		  },
		},
	*/
	fmt.Println("tags:", p.Tags())

	info, _ := p.Info("Name", "flag")
	dump.P(info)
	/*
		maputil.SMap { #len=4
		  "desc": string("set your name"), #len=13
		  "required": string("false"), #len=5
		  "default": string("INHERE"), #len=6
		  "shorts": string("n"), #len=1
		},
	*/

}
Output:

tags: map[Name:{flag:set your name;false;INHERE;n}]

func (*TagParser) ParseType added in v0.5.10

func (p *TagParser) ParseType(rt reflect.Type) error

ParseType parse a struct type value

func (*TagParser) Tags added in v0.5.10

func (p *TagParser) Tags() map[string]maputil.SMap

Tags map data for struct fields

type TagValFunc added in v0.5.10

type TagValFunc func(field, tagVal string) (maputil.SMap, error)

TagValFunc handle func

func ParseTagValueDefine added in v0.5.10

func ParseTagValueDefine(sep string, defines []string) TagValFunc

ParseTagValueDefine parse tag value string by given defines.

Examples:

eg: "desc;required;default;shorts"
type MyStruct {
	Age int `flag:"int option message;;a,b"`
}
sepStr := ";"
defines := []string{"desc", "required", "default", "shorts"}

type Value added in v0.5.5

type Value struct {
	// V value
	V any
}

Value data store

func NewValue added in v0.5.5

func NewValue(val any) *Value

NewValue instance.

func (*Value) Bool added in v0.5.5

func (v *Value) Bool() bool

Bool value

func (*Value) Float64 added in v0.5.5

func (v *Value) Float64() float64

Float64 value

func (*Value) Int added in v0.5.5

func (v *Value) Int() int

Int value get

func (*Value) Int64 added in v0.5.5

func (v *Value) Int64() int64

Int64 value

func (*Value) IsEmpty added in v0.5.5

func (v *Value) IsEmpty() bool

IsEmpty value

func (*Value) Reset added in v0.5.5

func (v *Value) Reset()

Reset value

func (*Value) Set added in v0.5.5

func (v *Value) Set(val any)

Set value

func (*Value) SplitToInts added in v0.5.6

func (v *Value) SplitToInts(sep ...string) (ss []int)

SplitToInts split string value to []int. sep default is comma(,)

func (*Value) SplitToStrings added in v0.5.6

func (v *Value) SplitToStrings(sep ...string) (ss []string)

SplitToStrings split string value to strings. sep default is comma(,)

func (*Value) String added in v0.5.5

func (v *Value) String() string

String value

func (*Value) Strings added in v0.5.5

func (v *Value) Strings() (ss []string)

Strings value

func (*Value) Val added in v0.5.5

func (v *Value) Val() any

Val get

type Wrapper added in v0.6.9

type Wrapper struct {

	// FieldTagName field name for read/write value. default tag: json
	FieldTagName string
	// contains filtered or unexported fields
}

Wrapper struct for read or set field value

func NewWrapper added in v0.6.9

func NewWrapper(src any) *Wrapper

NewWrapper create a struct wrapper

func NewWriter added in v0.6.9

func NewWriter(ptr any) *Wrapper

NewWriter create a struct writer

func Wrap added in v0.6.9

func Wrap(src any) *Wrapper

Wrap create a struct wrapper

func WrapValue added in v0.6.9

func WrapValue(rv reflect.Value) *Wrapper

WrapValue create a struct wrapper

func (*Wrapper) Get added in v0.6.9

func (r *Wrapper) Get(name string) any

Get field value by name, name allow use dot syntax.

func (*Wrapper) Lookup added in v0.6.9

func (r *Wrapper) Lookup(name string) (val any, ok bool)

Lookup field value by name, name allow use dot syntax.

func (*Wrapper) Set added in v0.6.11

func (r *Wrapper) Set(name string, val any) error

Set field value by name, name allow use dot syntax.

Jump to

Keyboard shortcuts

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