├── .github └── workflows │ └── go.yml ├── .gitignore ├── LICENSE.md ├── Makefile ├── README.md ├── default.go ├── default_test.go ├── error.go ├── example ├── array │ └── main.go ├── error_handle │ └── main.go ├── func │ └── main.go ├── interface │ └── main.go ├── json │ └── main.go ├── map │ └── main.go ├── nested │ └── main.go ├── simple │ └── main.go └── slice │ └── main.go ├── func.go ├── func_test.go ├── go.mod ├── go.sum ├── initializer.go ├── new.go ├── new_test.go ├── util.go └── util_test.go /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | 11 | test: 12 | name: Test 13 | runs-on: ubuntu-latest 14 | steps: 15 | 16 | - name: Set up Go 1.16.13 17 | uses: actions/setup-go@v1 18 | with: 19 | go-version: 1.16.13 20 | id: go 21 | 22 | - name: Check out code into the Go module directory 23 | uses: actions/checkout@v2 24 | 25 | - name: Go module download 26 | run: go mod download 27 | 28 | - name: Go UnitTest 29 | run: go test -short . 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | # Binaries for programs and plugins 3 | *.exe 4 | *.exe~ 5 | *.dll 6 | *.so 7 | *.dylib 8 | 9 | # Test binary, build with `go test -c` 10 | *.test 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ## THE BEER-WARE LICENSE (Revision 42) 2 | HellP(RebirthLee)<> wrote this software. As long as you 3 | retain this notice you can do whatever you want with this stuff. If we meet 4 | some day, and you think this stuff is worth it, you can buy me a beer in return. 5 | 6 | ## 비어웨어 라이센스 (개정 42) 7 | 헬프(이재성)<>이 이 소프트웨어를 작성했습니다. 8 | 당신은 이 통지를 보유하는 한 이 소프트웨어로 무엇이든 할 수 있습니다. 9 | 이게 가치가 있다고 생각하면, 만나서 보답으로 제게 맥주를 사줄 수 있습니다. 10 | 11 | 12 | [비어웨어 라이센스](http://en.wikipedia.org/wiki/Beerware)는 [Poul-Henning Kamp](http://people.freebsd.org/~phk/)에 의해 처음 작성되었습니다. 13 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | go test -v -cover -covermode=atomic . 3 | 4 | mod-download: 5 | go mod download 6 | 7 | unittest: 8 | go test -short . 9 | 10 | clean: 11 | if [ -f ${binary} ] ; then rm ${binary} ; fi 12 | 13 | lint-prepare: 14 | @echo "Installing golangci-lint" 15 | curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s latest 16 | 17 | lint: 18 | ./bin/golangci-lint run \ 19 | --exclude-use-default=false \ 20 | --enable=golint \ 21 | --enable=gocyclo \ 22 | --enable=goconst \ 23 | --enable=unconvert \ 24 | . -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # golang-default 2 | [![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2FRebirthLee%2Fgolang-default%2Fbadge%3Fref%3Dmaster&style=flat)](https://actions-badge.atrox.dev/RebirthLee/golang-default/goto?ref=master) 3 | [![GitHub release (latest by date)](https://img.shields.io/github/v/release/rebirthlee/golang-default)](https://github.com/RebirthLee/golang-default/releases) 4 | [![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/rebirthlee/golang-default)](https://golang.org/doc/go1.13) 5 | [![license](https://img.shields.io/badge/license-BEER--WARE-green)](/LICENSE.md) 6 | 7 | Initialize or New Struct with default value 8 | 9 | ## Setup 10 | ``` 11 | go get github.com/rebirthlee/golang-default 12 | ``` 13 | 14 | ## Support type 15 | - `int/8/16/32/64`, `uint/8/16/32/64` 16 | ```go 17 | `def:"100"` 18 | `def:"-100"` // support only signed integer 19 | // support hexadecimal, octal, binary 20 | `def:"0xff"` // hexadecimal 21 | `def:"0xFF"` // hexadecimal 22 | `def:"0o77"` // octal 23 | `def:"0b11001111"` // binary 24 | ``` 25 | - `float32/64` 26 | ```go 27 | `def:"3.141592653589"` 28 | `def:"-3.141592"` 29 | ``` 30 | - `complex64/128` 31 | ```go 32 | // `def:"{real part},{imaginary part}"` 33 | `def:"3.14,-10"` 34 | `def:"-3.14,3"` 35 | ``` 36 | 37 | - `time.Duration` 38 | ```go 39 | // calling time.ParseDuration 40 | `def:"1h"` // 1 * time.Hour 41 | ``` 42 | 43 | - `time.Time` 44 | ```go 45 | `def:"now"` // time.Now() 46 | `def:"+1h"` // time.Now().Add(1 * time.Hour) 47 | `def:"-1h"` // time.Now().Add(-1 * time.Hour) 48 | ``` 49 | 50 | - Nested Struct 51 | ```go 52 | type Parent struct { 53 | Name string `def:"Parent Struct"` 54 | OneChild Child `def:"dive"` 55 | TwoChild Child `def:"dive"` 56 | } 57 | 58 | type Child struct { 59 | Key string `def:"unknown"` 60 | Number int `def:"-1"` 61 | } 62 | ``` 63 | 64 | - Pointer of type 65 | ```go 66 | type Parent struct { 67 | Name *string `def:"Parent Struct"` 68 | OneChild *Child `def:"dive"` 69 | TwoChild *Child `def:"dive"` 70 | } 71 | 72 | type Child struct { 73 | Key *string `def:"unknown"` 74 | Number *int `def:"-1"` 75 | } 76 | ``` 77 | 78 | - Array 79 | ```go 80 | type Sample struct { 81 | Arr [3]int `def:"dive,-1"` // [-1, -1, -1] 82 | } 83 | ``` 84 | 85 | - Slice 86 | ```go 87 | type Sample struct { 88 | // `def:"dive({length},{capacity(optional)}),{value}"` 89 | Sli []int `def:"dive(5),-1"` // [-1, -1, -1, -1, -1] 90 | 91 | //cap(SliWithCap) == 7 92 | SliWithCap []NestedSample `def:"dive(3,7),dive"` // [{nested struct},{nested struct},{nested struct}] 93 | } 94 | 95 | type NestedSample struct { 96 | Name string `def:"nested struct"` 97 | } 98 | ``` 99 | 100 | - Map 101 | ```go 102 | type Sample struct { 103 | DiveMap map[string]*Struct `def:"dive{\"john doe\":dive,\"some one\":dive,\"key\":dive}"` 104 | /* 105 | { 106 | "john doe": &{who?}, 107 | "some one": &{who?}, 108 | "key": &{who?} 109 | } 110 | */ 111 | StructKeyMap map[*Struct]bool `def:"dive{dive:true,dive:false,dive:true}"` 112 | /* 113 | { 114 | &{who?}: true, 115 | &{who?}: false, 116 | &{who?}: true 117 | } 118 | */ 119 | DiveNestedMap map[string]map[*Struct]bool `def:"dive{\"key1\":dive{dive:true,dive:false},\"key2\":dive{dive:false,dive:false}}"` 120 | /* 121 | { 122 | "key1": { 123 | &{who?}: true, 124 | &{who?}: false 125 | }, 126 | "key2": { 127 | &{who?}: false, 128 | &{who?}: false 129 | } 130 | } 131 | */ 132 | } 133 | 134 | Struct struct { 135 | Name string `def:"who?"` 136 | } 137 | ``` 138 | 139 | - Json 140 | ```go 141 | type Sample struct { 142 | Arr [3]int `def:"[1,2,3]"` // [1,2,3] 143 | Sli []string `def:"[\"slice 1\",\"slice 2\"]"` // [slice 1,slice 2] 144 | Map map[string]interface{} `def:"{\"key1\":123,\"key2\":\"value\",\"nested map\":{\"key\":\"val\"}}"` 145 | /* 146 | { 147 | "key1":123, 148 | "key2":"value", 149 | "nested map":{ 150 | "key":"val" 151 | } 152 | } 153 | */ 154 | 155 | Nested NestedSample `def:"{\"displayName\":\"nested struct type\"}"` // {nested struct type} 156 | PtrNested *NestedSample `def:"{\"displayName\":\"nested struct pointer type\"}"` // &{nested struct pointer type} 157 | } 158 | 159 | type NestedSample struct { 160 | Name string `json:"displayName"` 161 | } 162 | ``` 163 | 164 | - Function 165 | 166 | [Example](/example/func/main.go) 167 | 168 | ## Usage 169 | ### Simple 170 | 171 | ```go 172 | import ( 173 | "fmt" 174 | "github.com/rebirthlee/golang-default" 175 | ) 176 | 177 | type Person struct { 178 | Age int `def:"20"` 179 | Name string `def:"hellp"` 180 | } 181 | 182 | ... 183 | var p Person 184 | if err := def.Init(&p); err != nil { 185 | // error handle 186 | } 187 | fmt.Println(p) //out: {20 hellp} 188 | ``` 189 | 190 | ### Init 191 | If you got error, the next field of struct will not be initialized. 192 | 193 | ```go 194 | if err := def.Init(&p); err != nil { 195 | // error handle 196 | } 197 | ``` 198 | 199 | ### JustInit 200 | Even though it has an error, It will try to initialize all fields. 201 | And you can know that error field of struct. 202 | 203 | ```go 204 | if err := def.JustInit(&p); err != nil { 205 | justErr := err.(*def.ErrorJustInit) 206 | fmt.Println(justErr.Error()) 207 | // error handle 208 | } 209 | ``` 210 | 211 | ### MustInit 212 | It isn't return error. but it will be panic when you has an error. 213 | 214 | ```go 215 | def.MustInit(&p) // hasn't return error. 216 | ``` 217 | 218 | ### New 219 | If you got error, it will be return nil. 220 | 221 | ```go 222 | i, err := def.New(Person{}) 223 | if err != nil { 224 | // error handle 225 | } else { 226 | p := i.(*Person) 227 | fmt.Println(p) //out: &{20 hellp} 228 | } 229 | ``` 230 | 231 | ### JustNew 232 | Even though it has an error, It must return pointer of struct with error. 233 | 234 | ```go 235 | i, err := def.JustNew(Person{}) 236 | if err != nil { 237 | justErr := err.(*def.ErrorJustInit) 238 | fmt.Println(justErr.Error()) 239 | // error handle 240 | } 241 | p := i.(*Person) 242 | fmt.Println(p) //out: &{20 hellp} 243 | ``` 244 | 245 | ### MustNew 246 | It isn't return error. but it will be panic when you has an error. 247 | 248 | ```go 249 | p := def.MustNew(Person{}).(*Person) // hasn't return error. 250 | fmt.Println(p) //out: &{20 hellp} 251 | ``` 252 | 253 | License 254 | --- 255 | [`THE BEER-WARE LICENSE (Revision 42)`](http://en.wikipedia.org/wiki/Beerware) 256 | -------------------------------------------------------------------------------- /default.go: -------------------------------------------------------------------------------- 1 | package def 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "reflect" 8 | "strconv" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | const ( 14 | tagNameDefault = "def" 15 | 16 | valueDive = "dive" 17 | valueDiveLen = len(valueDive) 18 | ) 19 | 20 | var ( 21 | timeDurationType = reflect.TypeOf(time.Duration(0)) 22 | timeType = reflect.TypeOf(time.Time{}) 23 | ) 24 | 25 | type structInitSelector func(v reflect.Value, visitedStruct map[reflect.Type]bool) error 26 | 27 | func checkPtr(i interface{}) (reflect.Value, error) { 28 | v := reflect.ValueOf(i) 29 | if v.Kind() != reflect.Ptr { 30 | return v, errors.New("param must be pointer") 31 | } 32 | 33 | return v, nil 34 | } 35 | 36 | func Init(i interface{}) error { 37 | v, err := checkPtr(i) 38 | if err != nil { 39 | return err 40 | } 41 | defer callInit(v) 42 | return initStruct(v.Elem(), maybeInit, make(map[reflect.Type]bool)) 43 | } 44 | 45 | func MustInit(i interface{}) { 46 | if err := Init(i); err != nil { 47 | panic(err) 48 | } 49 | } 50 | 51 | func JustInit(i interface{}) error { 52 | v, err := checkPtr(i) 53 | if err != nil { 54 | return err 55 | } 56 | defer callInit(v) 57 | return initStruct(v.Elem(), justInit, make(map[reflect.Type]bool)) 58 | } 59 | 60 | func initStruct(v reflect.Value, selector structInitSelector, visitedStruct map[reflect.Type]bool) error { 61 | if !v.CanSet() { 62 | return nil 63 | } 64 | 65 | t := v.Type() 66 | if visitedStruct[t] { 67 | return fmt.Errorf("struct type \"%s\" is cycle", t.Name()) 68 | } 69 | 70 | visitedStruct[t] = true 71 | defer delete(visitedStruct, t) 72 | return selector(v, visitedStruct) 73 | } 74 | 75 | func justInit(v reflect.Value, visitedStruct map[reflect.Type]bool) error { 76 | fieldErrors := make([]*ErrorJustInitField, 0) 77 | t := v.Type() 78 | for i := 0; i < t.NumField(); i++ { 79 | if val := t.Field(i).Tag.Get(tagNameDefault); val != "-" { 80 | if err := initField(v, v.Field(i), val, justInit, visitedStruct); err != nil { 81 | ft := t.Field(i) 82 | typeName := ft.Type.Name() 83 | if ft.Type.PkgPath() != "" { 84 | typeName = ft.Type.PkgPath() + "." + typeName 85 | } 86 | fieldErrors = append(fieldErrors, &ErrorJustInitField{ 87 | StructName: t.PkgPath()+"."+t.Name(), 88 | FieldName: ft.Name, 89 | FieldType: typeName, 90 | TryValue: val, 91 | Cause: err, 92 | Target: v.Field(i), 93 | }) 94 | } 95 | } 96 | } 97 | 98 | if len(fieldErrors) > 0 { 99 | return &ErrorJustInit{Errors:fieldErrors} 100 | } 101 | 102 | return nil 103 | } 104 | 105 | func maybeInit(v reflect.Value, visitedStruct map[reflect.Type]bool) error { 106 | t := v.Type() 107 | for i := 0; i < t.NumField(); i++ { 108 | if val := t.Field(i).Tag.Get(tagNameDefault); val != "-" { 109 | if err := initField(v, v.Field(i), val, maybeInit, visitedStruct); err != nil { 110 | return err 111 | } 112 | } 113 | } 114 | 115 | return nil 116 | } 117 | 118 | 119 | func initField(structVal reflect.Value, fieldVal reflect.Value, defVal string, selector structInitSelector, visitedStruct map[reflect.Type]bool) error { 120 | if !fieldVal.CanSet() { 121 | return nil 122 | } 123 | 124 | fieldType := fieldVal.Type() 125 | 126 | //special type 127 | switch fieldType { 128 | case timeDurationType: 129 | if d, err := time.ParseDuration(defVal); err != nil { 130 | return err 131 | } else { 132 | fieldVal.Set(reflect.ValueOf(d)) 133 | return nil 134 | } 135 | case timeType: 136 | if defVal == "now" { 137 | fieldVal.Set(reflect.ValueOf(time.Now())) 138 | return nil 139 | } else if strings.HasPrefix(defVal, "+") || strings.HasPrefix(defVal, "-") { 140 | d, err := time.ParseDuration(defVal) 141 | if err != nil { 142 | return err 143 | } 144 | 145 | fieldVal.Set(reflect.ValueOf(time.Now().Add(d))) 146 | return nil 147 | } 148 | } 149 | 150 | k := fieldVal.Kind() 151 | 152 | // maybe Init function callable type 153 | switch k { 154 | case reflect.Ptr: 155 | elem := fieldVal.Elem() 156 | if elem.Kind() == reflect.Invalid { 157 | fieldVal.Set(reflect.New(fieldType.Elem())) 158 | elem = fieldVal.Elem() 159 | } 160 | if elem.Kind() != reflect.Struct { 161 | defer callInit(fieldVal) 162 | } 163 | return initField(structVal, elem, defVal, selector, visitedStruct) 164 | case reflect.Struct: 165 | if fieldVal.CanAddr() { 166 | defer callInit(fieldVal) 167 | } 168 | 169 | if defVal == valueDive { 170 | return initStruct(fieldVal, selector, visitedStruct) 171 | } else if defVal != "" { 172 | if err := jsonUnmarshalValue(fieldVal, defVal); err != nil { 173 | return err 174 | } 175 | } 176 | } 177 | 178 | if defVal == "" { 179 | return nil 180 | } 181 | 182 | // primitive type 183 | switch k { 184 | case reflect.Invalid: 185 | return nil 186 | case reflect.String: 187 | fieldVal.SetString(defVal) 188 | case reflect.Bool: 189 | if b, err := strconv.ParseBool(defVal); err != nil { 190 | return err 191 | } else { 192 | fieldVal.SetBool(b) 193 | } 194 | case reflect.Int, reflect.Int8, reflect.Int16, 195 | reflect.Int32, reflect.Int64: 196 | if i, err := strconv.ParseInt(getBaseValue(defVal)); err != nil { 197 | return err 198 | } else { 199 | fieldVal.SetInt(i) 200 | } 201 | case reflect.Uint, reflect.Uint8, reflect.Uint16, 202 | reflect.Uint32, reflect.Uint64: 203 | if i, err := strconv.ParseUint(getBaseValue(defVal)); err != nil { 204 | return err 205 | } else { 206 | fieldVal.SetUint(i) 207 | } 208 | case reflect.Float32, reflect.Float64: 209 | if f, err := strconv.ParseFloat(defVal, 0); err != nil { 210 | return err 211 | } else { 212 | fieldVal.SetFloat(f) 213 | } 214 | case reflect.Complex64, reflect.Complex128: 215 | vals := strings.Split(defVal,",") 216 | if len(vals) != 2 { 217 | return errors.New("only two args") 218 | } 219 | if c, err := getStringToComplex(vals[0], vals[1]); err != nil { 220 | return err 221 | } else { 222 | fieldVal.SetComplex(c) 223 | } 224 | case reflect.Interface: 225 | if defVal == "" { 226 | fieldVal.Set(reflect.Zero(fieldType)) 227 | } else if err := jsonUnmarshalValue(fieldVal, defVal); err != nil { 228 | return err 229 | } 230 | case reflect.Map: 231 | if strings.HasPrefix(defVal, valueDive+"{") && strings.HasSuffix(defVal, "}") { 232 | keyType := fieldType.Key() 233 | valType := fieldType.Elem() 234 | 235 | fieldVal.Set(reflect.MakeMap(fieldType)) 236 | 237 | tmp := defVal[valueDiveLen+1:len(defVal)-1] 238 | flag := byte(0x00) 239 | keyIndex := len(tmp) 240 | valIndex := 0 241 | set := func(targetVal reflect.Value, start int, end int) error { 242 | return initField(structVal, targetVal, tmp[start:end], selector, visitedStruct) 243 | } 244 | 245 | for i := len(tmp)-1; i >= 0; i-- { 246 | c := tmp[i] 247 | switch flag { 248 | case 0x00: // none 249 | if c == '"' { 250 | //flag ^= 0x01 251 | flag = 0x01 252 | } else if c == '}' { 253 | flag = 0x02 254 | } 255 | case 0x01: // isString 256 | if c == '"' { 257 | //flag ^= 0x01 258 | flag = 0x00 259 | } 260 | case 0x02: // isObject 261 | if c == '{' { 262 | flag = 0x00 263 | } 264 | } 265 | 266 | if flag > 0 { 267 | continue 268 | } 269 | 270 | if c == ':' { 271 | valIndex = i 272 | } else if c == ',' || i == 0 { 273 | var at int 274 | if i > valIndex { 275 | return errors.New("map default value malformed format") 276 | } else if i == 0 { 277 | at = i 278 | } else { 279 | at = i + 1 280 | } 281 | 282 | 283 | keyRef := reflect.New(keyType) 284 | valRef := reflect.New(valType) 285 | if keyErr, valErr := set(keyRef.Elem(), at, valIndex), set(valRef.Elem(), valIndex+1, keyIndex); keyErr != nil { 286 | return keyErr 287 | } else if valErr != nil { 288 | return valErr 289 | } 290 | fieldVal.SetMapIndex(keyRef.Elem(), valRef.Elem()) 291 | keyIndex = i 292 | } 293 | } 294 | 295 | } else if err := jsonUnmarshalValue(fieldVal, defVal); err != nil { 296 | return err 297 | } 298 | case reflect.Slice: 299 | if strings.HasPrefix(defVal, valueDive+"(") { 300 | tmp := defVal[valueDiveLen+1:] 301 | endBracket := strings.Index(tmp, ")") 302 | if endBracket < 0 { 303 | return errors.New("you must close bracket ')'") 304 | } 305 | 306 | ln, cp := 0, 0 307 | sizes := strings.SplitN(tmp[:endBracket], ",", 2) 308 | switch l := len(sizes); l { 309 | default: 310 | return errors.New("must be \"dive(len)\" or \"dive(len,cap)\"") 311 | case 2: 312 | if strings.HasPrefix("-", sizes[0]) || strings.HasPrefix("-", sizes[1]) { 313 | return errors.New("negative size, param must be 0 or more") 314 | } 315 | 316 | var parseErr error 317 | ln, parseErr = strconv.Atoi(sizes[0]) 318 | if parseErr != nil { 319 | return parseErr 320 | } 321 | 322 | cp, parseErr = strconv.Atoi(sizes[1]) 323 | if parseErr != nil { 324 | return parseErr 325 | } 326 | 327 | if ln > cp { 328 | return errors.New("len larger than cap") 329 | } 330 | case 1: 331 | if strings.HasPrefix("-", sizes[0]) { 332 | return errors.New("negative size, param must be 0 or more") 333 | } 334 | 335 | var parseErr error 336 | ln, parseErr = strconv.Atoi(sizes[0]) 337 | if parseErr != nil { 338 | return parseErr 339 | } 340 | 341 | cp = int(float64(ln) * 1.5) 342 | } 343 | 344 | val := tmp[endBracket+1:] 345 | if !strings.HasPrefix(val, ",") { 346 | return errors.New("not enough arguments") 347 | } 348 | val = val[1:] 349 | 350 | fieldVal.Set(reflect.MakeSlice(fieldType, ln, cp)) 351 | for i := 0; i < ln; i++ { 352 | if err := initField(structVal, fieldVal.Index(i), val, selector, visitedStruct); err != nil { 353 | return err 354 | } 355 | } 356 | } else if err := jsonUnmarshalValue(fieldVal, defVal); err != nil { 357 | return err 358 | } 359 | case reflect.Array: 360 | if strings.HasPrefix(defVal, valueDive) { 361 | val := defVal[valueDiveLen:] 362 | if !strings.HasPrefix(val, ",") { 363 | return errors.New("not enough arguments") 364 | } 365 | val = val[1:] 366 | for i, cnt := 0, fieldVal.Len(); i < cnt; i++ { 367 | if err := initField(structVal, fieldVal.Index(i), val, selector, visitedStruct); err != nil { 368 | return err 369 | } 370 | } 371 | } else if err := jsonUnmarshalValue(fieldVal, defVal); err != nil { 372 | return err 373 | } 374 | return nil 375 | case reflect.Chan: 376 | if strings.HasPrefix(defVal, "-") { 377 | return errors.New("negative buffer size, param must be 0 or more") 378 | } else if i, err := strconv.Atoi(defVal); err != nil { 379 | return err 380 | } else { 381 | fieldVal.Set(reflect.MakeChan(fieldType, i)) 382 | } 383 | case reflect.Func: 384 | srcFunc, ok := funcMap[defVal] 385 | if !structVal.CanAddr() { 386 | return errors.New("function initialize failed, because can't access address of struct") 387 | } else if !ok { 388 | return fmt.Errorf("not exists key : \"%s\"", defVal) 389 | } 390 | 391 | srcFuncVal := reflect.ValueOf(srcFunc) 392 | if srcFuncVal.Type().In(0) != structVal.Addr().Type() { 393 | return errors.New("function in type is wrong") 394 | } 395 | 396 | srcVal := srcFuncVal.Call([]reflect.Value{structVal.Addr()})[0].Elem() 397 | srcType := srcVal.Type() 398 | if srcType.Kind() != reflect.Func { 399 | return errors.New("return value must be function type") 400 | } 401 | vType := fieldType 402 | if vType.NumIn() != srcType.NumIn() { 403 | return errors.New("args count not equal") 404 | } else if vType.NumOut() != srcType.NumOut() { 405 | return errors.New("returns count not equal") 406 | } 407 | 408 | for i, cnt := 0, vType.NumIn(); i < cnt; i++ { 409 | if vType.In(i) != srcType.In(i) { 410 | return fmt.Errorf("(argument at %d) wrong argument type, dest func arg type \"%s::%s\", src func arg type \"%s::%s\"", i, 411 | vType.In(i).PkgPath(), vType.In(i).Name(), srcType.In(i).PkgPath(), srcType.In(i).Name()) 412 | } 413 | } 414 | 415 | for i, cnt := 0, vType.NumOut(); i < cnt; i++ { 416 | if vType.Out(i) != srcType.Out(i) { 417 | return fmt.Errorf("(argument at %d) wrong argument type, dest func arg type \"%s::%s\", src func arg type \"%s::%s\"", i, 418 | vType.Out(i).PkgPath(), vType.Out(i).Name(), srcType.Out(i).PkgPath(), srcType.Out(i).Name()) 419 | } 420 | } 421 | 422 | fieldVal.Set(srcVal) 423 | } 424 | 425 | 426 | return nil 427 | } 428 | 429 | func jsonUnmarshalValue(v reflect.Value, obj string) error { 430 | if !v.CanAddr() { 431 | return errors.New("json unmarshal fail, because can't access address of field") 432 | } else if err := json.Unmarshal([]byte(obj), v.Addr().Interface()); err != nil { 433 | return err 434 | } 435 | 436 | return nil 437 | } 438 | 439 | func callInit(v reflect.Value) { 440 | if init, ok := v.Interface().(Initializer); ok && init != nil { 441 | init.Init() 442 | } 443 | } -------------------------------------------------------------------------------- /default_test.go: -------------------------------------------------------------------------------- 1 | package def 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "reflect" 6 | "testing" 7 | ) 8 | 9 | type initSample struct { 10 | number int 11 | name string 12 | } 13 | 14 | func (i *initSample) Init() { 15 | i.name = "init test" 16 | i.number = 1111 17 | } 18 | 19 | func Test_checkPtr(t *testing.T) { 20 | var typeInt int 21 | typeInt = 123 22 | v, err := checkPtr(typeInt) 23 | if assert.Error(t, err) { 24 | valueOfInt := reflect.ValueOf(typeInt) 25 | assert.Equal(t, v.Type(), valueOfInt.Type()) 26 | assert.Equal(t, v.Int(), valueOfInt.Int()) 27 | } 28 | 29 | v, err = checkPtr(&typeInt) 30 | if assert.NoError(t, err) { 31 | valueOfInt := reflect.ValueOf(&typeInt) 32 | assert.Equal(t, v.Elem().Type(), valueOfInt.Elem().Type()) 33 | assert.Equal(t, v.Pointer(), valueOfInt.Pointer()) 34 | } 35 | } 36 | 37 | func Test_callInit(t *testing.T) { 38 | i := initSample{} 39 | callInit(reflect.ValueOf(&i)) 40 | assert.Equal(t, i.name, "init test") 41 | assert.Equal(t, i.number, 1111) 42 | } 43 | 44 | func Test_initField(t *testing.T) { 45 | //assert.NoError(t, initField(reflect.Value{}, false, nil, nil)) 46 | //assert.NoError(t, initField(reflect.ValueOf(0), true, nil, nil)) 47 | } 48 | 49 | func TestInit(t *testing.T) { 50 | 51 | { 52 | sample := sample{} 53 | err := Init(&sample) 54 | if assert.NoError(t, err) { 55 | checkSample(t, &sample) 56 | } 57 | } 58 | 59 | { 60 | sample := sample{} 61 | err := Init(sample) 62 | assert.Error(t, err) 63 | } 64 | 65 | { 66 | sample := nestedSample{} 67 | err := Init(&sample) 68 | if assert.NoError(t, err) { 69 | assert.Equal(t, sample.Name, "this is nested sample") 70 | if assert.NotNil(t, sample.Psample) { 71 | checkSample(t, sample.Psample) 72 | } 73 | checkSample(t, &sample.Sample) 74 | } 75 | } 76 | 77 | { 78 | sample := jsonSample{} 79 | err := Init(&sample) 80 | if assert.NoError(t, err) { 81 | assert.Equal(t, sample.Name, "this is json struct sample") 82 | 83 | assert.Equal(t, sample.Json.Name, "rebirth lee") 84 | assert.Equal(t, sample.Json.Age, 25) 85 | 86 | if assert.NotNil(t, sample.Pjson) { 87 | assert.Equal(t, sample.Pjson.Name, "lee rebirth") 88 | assert.Equal(t, sample.Pjson.Age, 52) 89 | } 90 | } 91 | } 92 | 93 | { 94 | errorCheckList := []interface{}{ 95 | &cycleErrorSample{}, 96 | &boolErrorSample{}, 97 | &intErrorSample{}, 98 | &uintErrorSample{}, 99 | &floatErrorSample{}, 100 | &complexErrorSample{}, 101 | &complexFailParseError1Sample{}, 102 | &complexFailParseError2Sample{}, 103 | &chanErrorSample{}, 104 | &chanFailParseErrorSample{}, 105 | } 106 | 107 | for i := range errorCheckList { 108 | err := Init(errorCheckList[i]) 109 | assert.Error(t, err) 110 | } 111 | } 112 | } 113 | 114 | func TestJustInit(t *testing.T) { 115 | 116 | { 117 | sample := sample{} 118 | err := JustInit(&sample) 119 | if assert.NoError(t, err) { 120 | checkSample(t, &sample) 121 | } 122 | } 123 | 124 | { 125 | sample := sample{} 126 | err := JustInit(sample) 127 | assert.Error(t, err) 128 | } 129 | 130 | { 131 | sample := nestedSample{} 132 | err := JustInit(&sample) 133 | if assert.NoError(t, err) { 134 | assert.Equal(t, sample.Name, "this is nested sample") 135 | if assert.NotNil(t, sample.Psample) { 136 | checkSample(t, sample.Psample) 137 | } 138 | checkSample(t, &sample.Sample) 139 | } 140 | } 141 | 142 | { 143 | sample := jsonSample{} 144 | err := JustInit(&sample) 145 | if assert.NoError(t, err) { 146 | assert.Equal(t, sample.Name, "this is json struct sample") 147 | 148 | assert.Equal(t, sample.Json.Name, "rebirth lee") 149 | assert.Equal(t, sample.Json.Age, 25) 150 | 151 | if assert.NotNil(t, sample.Pjson) { 152 | assert.Equal(t, sample.Pjson.Name, "lee rebirth") 153 | assert.Equal(t, sample.Pjson.Age, 52) 154 | } 155 | } 156 | } 157 | 158 | { 159 | errorCheckList := []interface{}{ 160 | &cycleErrorSample{}, 161 | &boolErrorSample{}, 162 | &intErrorSample{}, 163 | &uintErrorSample{}, 164 | &floatErrorSample{}, 165 | &complexErrorSample{}, 166 | &complexFailParseError1Sample{}, 167 | &complexFailParseError2Sample{}, 168 | &chanErrorSample{}, 169 | &chanFailParseErrorSample{}, 170 | } 171 | 172 | for i := range errorCheckList { 173 | err := JustInit(errorCheckList[i]) 174 | assert.Error(t, err) 175 | } 176 | } 177 | } 178 | 179 | 180 | func TestMustInit(t *testing.T) { 181 | 182 | { 183 | sample := sample{} 184 | MustInit(&sample) 185 | checkSample(t, &sample) 186 | } 187 | 188 | { 189 | sample := sample{} 190 | assert.Panics(t, func() { 191 | MustInit(sample) 192 | }) 193 | } 194 | 195 | { 196 | sample := nestedSample{} 197 | MustInit(&sample) 198 | assert.Equal(t, sample.Name, "this is nested sample") 199 | if assert.NotNil(t, sample.Psample) { 200 | checkSample(t, sample.Psample) 201 | } 202 | checkSample(t, &sample.Sample) 203 | } 204 | 205 | { 206 | sample := jsonSample{} 207 | MustInit(&sample) 208 | assert.Equal(t, sample.Name, "this is json struct sample") 209 | 210 | assert.Equal(t, sample.Json.Name, "rebirth lee") 211 | assert.Equal(t, sample.Json.Age, 25) 212 | 213 | if assert.NotNil(t, sample.Pjson) { 214 | assert.Equal(t, sample.Pjson.Name, "lee rebirth") 215 | assert.Equal(t, sample.Pjson.Age, 52) 216 | } 217 | } 218 | 219 | { 220 | errorCheckList := []interface{}{ 221 | &cycleErrorSample{}, 222 | &boolErrorSample{}, 223 | &intErrorSample{}, 224 | &uintErrorSample{}, 225 | &floatErrorSample{}, 226 | &complexErrorSample{}, 227 | &complexFailParseError1Sample{}, 228 | &complexFailParseError2Sample{}, 229 | &chanErrorSample{}, 230 | &chanFailParseErrorSample{}, 231 | } 232 | 233 | for i := range errorCheckList { 234 | assert.Panics(t, func() { 235 | MustInit(errorCheckList[i]) 236 | }) 237 | } 238 | } 239 | } 240 | 241 | func Test_jsonUnmarshalValue(t *testing.T) { 242 | var val struct { 243 | Field map[string]interface{} 244 | } 245 | assert.Error(t, jsonUnmarshalValue(reflect.ValueOf(val).Field(0), "")) 246 | assert.Error(t, jsonUnmarshalValue(reflect.ValueOf(&val).Elem().Field(0), "}{")) 247 | assert.NoError(t, jsonUnmarshalValue(reflect.ValueOf(&val).Elem().Field(0), "{}")) 248 | } -------------------------------------------------------------------------------- /error.go: -------------------------------------------------------------------------------- 1 | package def 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "strings" 7 | ) 8 | 9 | type ( 10 | ErrorJustInit struct { 11 | Errors []*ErrorJustInitField 12 | } 13 | 14 | ErrorJustInitField struct { 15 | StructName string 16 | FieldName string 17 | FieldType string 18 | TryValue string 19 | Cause error 20 | Target reflect.Value 21 | } 22 | ) 23 | 24 | func (e *ErrorJustInit) Error() string { 25 | builder := strings.Builder{} 26 | builder.WriteString("Struct Errors\n") 27 | for i := range e.Errors { 28 | builder.WriteString("\t"+e.Errors[i].Error()) 29 | } 30 | return builder.String() 31 | } 32 | 33 | 34 | func (j *ErrorJustInitField) Error() string { 35 | return fmt.Sprintf("struct:%s,field:(%s %s),try:%s,error:%s", 36 | j.StructName, j.FieldName, j.FieldType, j.TryValue, strings.ReplaceAll(j.Cause.Error(), "\n", "\n\t")) 37 | } -------------------------------------------------------------------------------- /example/array/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/rebirthlee/golang-default" 6 | ) 7 | 8 | type ( 9 | Sample struct { 10 | Arr [3]NestedSample `def:"dive,dive"` 11 | Numbers [3]int `def:"dive,32000"` 12 | } 13 | 14 | NestedSample struct { 15 | Number int `def:"777"` 16 | Name string `def:"Nested Sample"` 17 | } 18 | ) 19 | 20 | 21 | func main() { 22 | sample := def.MustNew(Sample{}).(*Sample) 23 | fmt.Println(sample) 24 | } 25 | -------------------------------------------------------------------------------- /example/error_handle/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | def "github.com/rebirthlee/golang-default" 6 | ) 7 | 8 | type ( 9 | ErrorSample struct { 10 | Number int `def:"string"` 11 | } 12 | 13 | NestedErrorSample struct { 14 | Number int `def:"string"` 15 | Nest ErrorSample `def:"dive"` 16 | } 17 | ) 18 | 19 | func main() { 20 | sample := ErrorSample{} 21 | err := def.Init(&sample) 22 | if err != nil { 23 | fmt.Println(err.Error()) 24 | } 25 | 26 | err = def.JustInit(&sample) 27 | if err != nil { 28 | justErr := err.(*def.ErrorJustInit) 29 | fmt.Println(justErr.Error()) 30 | 31 | for i := range justErr.Errors { 32 | fieldErr := justErr.Errors[i] 33 | fmt.Println(fieldErr.Error()) 34 | //or do something 35 | } 36 | } 37 | 38 | println() 39 | println() 40 | 41 | nested := NestedErrorSample{} 42 | err = def.JustInit(&nested) 43 | if err != nil { 44 | justErr := err.(*def.ErrorJustInit) 45 | for i := range justErr.Errors { 46 | fieldErr := justErr.Errors[i] 47 | //do something 48 | 49 | nestedErr, ok := fieldErr.Cause.(*def.ErrorJustInit) 50 | if ok { 51 | fmt.Println(nestedErr.Error()) 52 | // more do something 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /example/func/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/rebirthlee/golang-default" 6 | ) 7 | 8 | type Person struct { 9 | Age int `def:"20"` 10 | Name string `def:"hellp"` 11 | Do func() string `def:"person_default_do"` 12 | } 13 | 14 | func init() { 15 | if err := def.SetFunc("person_default_do", func(self *Person) interface{} { 16 | return self.IntroducingMySelf 17 | }); err != nil { 18 | panic(err) 19 | } 20 | } 21 | 22 | func main() { 23 | p := def.MustNew(Person{}).(*Person) 24 | fmt.Println(p) 25 | fmt.Println(p.Do()) 26 | p.Name = "rebirth lee" 27 | p.Age = 25 28 | fmt.Println(p.Do()) 29 | } 30 | 31 | 32 | func (p *Person) IntroducingMySelf() string { 33 | return fmt.Sprintf("My name is %s, %d years old", p.Name, p.Age) 34 | } -------------------------------------------------------------------------------- /example/interface/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | def "github.com/rebirthlee/golang-default" 6 | ) 7 | 8 | type InitString string 9 | 10 | type Sample struct { 11 | ExportField string `def:"export field"` 12 | notExportField string 13 | StringField *InitString 14 | } 15 | 16 | func (i *InitString) Init() { 17 | fmt.Printf("InitString(%p) call Init\n", i) 18 | *i = "Hello String Field" 19 | } 20 | 21 | func (s *Sample) Init() { 22 | fmt.Printf("Sample(%p) call Init\n", s) 23 | s.notExportField = "not export field" 24 | } 25 | 26 | func main() { 27 | 28 | { 29 | // New 30 | i, err := def.New(Sample{}) 31 | if err == nil { 32 | s := i.(*Sample) 33 | showFields(s) 34 | } 35 | } 36 | 37 | { 38 | // MustNew 39 | s := def.MustNew(Sample{}).(*Sample) 40 | showFields(s) 41 | } 42 | 43 | { 44 | // JustNew 45 | i, err := def.JustNew(Sample{}) 46 | if err == nil { 47 | s := i.(*Sample) 48 | showFields(s) 49 | } 50 | } 51 | 52 | { 53 | // Init 54 | s := Sample{} 55 | if err := def.Init(&s); err != nil { 56 | // ...err 57 | fmt.Println("Init, Handle Error") 58 | } else { 59 | showFields(&s) 60 | } 61 | } 62 | 63 | { 64 | // MustInit 65 | s := Sample{} 66 | def.MustInit(&s) 67 | showFields(&s) 68 | } 69 | 70 | { 71 | // JustInit 72 | s := Sample{} 73 | if err := def.JustInit(&s); err != nil { 74 | // ...err 75 | fmt.Println("JustInit, Handle Error") 76 | } else { 77 | showFields(&s) 78 | } 79 | } 80 | } 81 | 82 | func showFields(s *Sample) { 83 | fmt.Printf("Struct Address : %p\n", s) 84 | fmt.Println("p.ExportField :", s.ExportField) 85 | fmt.Println("p.notExportField :", s.notExportField) 86 | fmt.Printf("p.StringField : %p\n", s.StringField) 87 | fmt.Println("*p.StringField :", *s.StringField) 88 | println() 89 | println() 90 | } -------------------------------------------------------------------------------- /example/json/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | def "github.com/rebirthlee/golang-default" 6 | ) 7 | 8 | type ( 9 | Sample struct { 10 | Interface interface{} `def:"{\"name\":\"rebirth lee\",\"age\":25}"` 11 | MapJson map[string]interface{} `def:"{\"items\":[\"item - 1\",\"item - 2\"]}"` 12 | 13 | NestedStruct Struct `def:"{\"title\":\"Struct Convert Json Test\",\"subtitle\":\"This is Struct\",\"num\":123}"` 14 | PtrNestedStruct *Struct `def:"{\"title\":\"Struct Pointer Convert Json Test\",\"subtitle\":\"This is Struct Pointer\",\"num\":321}"` 15 | } 16 | 17 | Struct struct { 18 | Title string `json:"title"` 19 | SubTitle string `json:"subtitle"` 20 | Number int `json:"num"` 21 | } 22 | ) 23 | 24 | func main() { 25 | s := def.MustNew(Sample{}).(*Sample) 26 | fmt.Println(s) 27 | fmt.Println(s.Interface) 28 | fmt.Println(s.MapJson) 29 | fmt.Println(s.NestedStruct) 30 | fmt.Println(s.PtrNestedStruct) 31 | } 32 | -------------------------------------------------------------------------------- /example/map/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | def "github.com/rebirthlee/golang-default" 6 | ) 7 | 8 | type ( 9 | NestedMap struct { 10 | PtrStructVal map[string]*Struct `def:"dive{\"john doe\":dive,\"some one\":dive,\"key\":dive}"` 11 | PtrStructKey map[*Struct]bool `def:"dive{dive:true,dive:true,dive:true}"` 12 | MapVal map[string]map[*Struct]bool `def:"dive{\"key1\":dive{dive:true,dive:false},\"key2\":dive{dive:false,dive:false}}"` 13 | } 14 | 15 | Struct struct { 16 | Name string `def:"who?"` 17 | } 18 | ) 19 | 20 | func main() { 21 | n := def.MustNew(NestedMap{}).(*NestedMap) 22 | fmt.Println(n) 23 | 24 | fmt.Println("---------PtrStructVal---------") 25 | for key, val := range n.PtrStructVal { 26 | fmt.Printf("%+v : %+v\n", key, val) 27 | } 28 | 29 | fmt.Println("---------PtrStructKey---------") 30 | for key, val := range n.PtrStructKey { 31 | fmt.Printf("%+v : %+v\n", key, val) 32 | } 33 | 34 | fmt.Println("---------MapVal---------") 35 | for key, val := range n.MapVal { 36 | fmt.Printf("MapVal[%s]\n", key) 37 | for inKey, inVal := range val { 38 | fmt.Printf("\t%+v : %+v\n", inKey, inVal) 39 | 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /example/nested/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/rebirthlee/golang-default" 6 | ) 7 | 8 | type ( 9 | Person struct { 10 | Age int `def:"-"` 11 | Name string `def:"rich guy"` 12 | Wallet *Wallet `def:"dive"` 13 | } 14 | 15 | Wallet struct { 16 | BrandName string `def:"Louis Vuitton"` 17 | Name *string `def:"unknown"` 18 | Money *int `def:"-"` 19 | Weight *int `def:"-"` 20 | } 21 | ) 22 | 23 | func main() { 24 | { 25 | // Nested - New 26 | i, err := def.New(Person{}) 27 | if err == nil { 28 | p := i.(*Person) 29 | fmt.Println(p) 30 | fmt.Println(p.Wallet) 31 | } 32 | } 33 | 34 | { 35 | // Nested - MustNew 36 | p := def.MustNew(Person{}).(*Person) 37 | fmt.Println(p) 38 | fmt.Println(p.Wallet) 39 | } 40 | 41 | { 42 | // Nested - JustNew 43 | //TODO 44 | } 45 | 46 | { 47 | // Nested - Init 48 | p := Person{} 49 | if err := def.Init(&p); err != nil { 50 | // ...err 51 | fmt.Println("Init, Handle Error") 52 | } else { 53 | fmt.Println(p) 54 | fmt.Println(p.Wallet) 55 | } 56 | } 57 | 58 | { 59 | // Nested - MustInit 60 | p := Person{} 61 | def.MustInit(&p) 62 | fmt.Println(p) 63 | fmt.Println(p.Wallet) 64 | } 65 | 66 | { 67 | // Nested - JustInit 68 | //TODO 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /example/simple/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/rebirthlee/golang-default" 6 | "time" 7 | ) 8 | 9 | type Person struct { 10 | Age int `def:"20"` 11 | Name string `def:"rebirth lee"` 12 | PocketName *string `def:"bitcoin"` 13 | AliveTime time.Duration `def:"175200h"` 14 | CreateAt time.Time `def:"now"` 15 | After1Hour time.Time `def:"+1h"` 16 | Before1Hour time.Time `def:"-1h"` 17 | } 18 | 19 | func main() { 20 | 21 | { 22 | // Simple - New 23 | i, err := def.New(Person{}) 24 | if err == nil { 25 | p := i.(*Person) 26 | fmt.Println(p) 27 | } 28 | } 29 | 30 | { 31 | // Simple - MustNew 32 | p := def.MustNew(Person{}).(*Person) 33 | fmt.Println(p) 34 | } 35 | 36 | { 37 | // Simple - JustNew 38 | i, err := def.JustNew(Person{}) 39 | if err == nil { 40 | p := i.(*Person) 41 | fmt.Println(p) 42 | } 43 | } 44 | 45 | { 46 | // Simple - Init 47 | p := Person{} 48 | if err := def.Init(&p); err != nil { 49 | // ...err 50 | fmt.Println("Init, Handle Error") 51 | } else { 52 | fmt.Println(p) 53 | } 54 | } 55 | 56 | { 57 | // Simple - MustInit 58 | p := Person{} 59 | def.MustInit(&p) 60 | fmt.Println(p) 61 | } 62 | 63 | { 64 | // Simple - JustInit 65 | p := Person{} 66 | if err := def.JustInit(&p); err != nil { 67 | // ...err 68 | fmt.Println("JustInit, Handle Error") 69 | } else { 70 | fmt.Println(p) 71 | } 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /example/slice/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | def "github.com/rebirthlee/golang-default" 6 | ) 7 | 8 | type ( 9 | Sample struct { 10 | Sli []NestedSample `def:"dive(3,7),dive"` 11 | Numbers []int `def:"dive(5),-32000"` 12 | } 13 | 14 | NestedSample struct { 15 | Number int `def:"333"` 16 | Name string `def:"Sample Nested"` 17 | } 18 | ) 19 | 20 | 21 | func main() { 22 | sample := def.MustNew(Sample{}).(*Sample) 23 | fmt.Println(sample) 24 | fmt.Printf("sample.Sli len = %d, cap = %d\n", len(sample.Sli), cap(sample.Sli)) 25 | fmt.Printf("sample.Numbers len = %d, cap = %d\n", len(sample.Numbers), cap(sample.Numbers)) 26 | } 27 | 28 | -------------------------------------------------------------------------------- /func.go: -------------------------------------------------------------------------------- 1 | package def 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | ) 8 | 9 | var ( 10 | funcMap = make(map[string]interface{}) 11 | ) 12 | 13 | func SetFunc(key string, fun interface{}) error { 14 | t := reflect.TypeOf(fun) 15 | if t.Kind() != reflect.Func { 16 | return errors.New("it is not function") 17 | } else if t.NumIn() != 1 { 18 | return errors.New("function in count must be 1") 19 | } else if t.In(0).Kind() != reflect.Ptr { 20 | return errors.New("function in param must pointer") 21 | } else if _, ok := funcMap[key]; ok { 22 | return fmt.Errorf("key \"%s\" is already has", key) 23 | } 24 | 25 | funcMap[key] = fun 26 | return nil 27 | } -------------------------------------------------------------------------------- /func_test.go: -------------------------------------------------------------------------------- 1 | package def 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "testing" 6 | ) 7 | 8 | 9 | func TestSetFunc(t *testing.T) { 10 | assert.NoError(t, SetFunc("key", func(self *sample) interface{} { 11 | return func() {} 12 | })) 13 | assert.Error(t, SetFunc("key", func(self *sample) interface{} { 14 | return func() {} 15 | })) 16 | assert.Error(t, SetFunc("error1", func(self interface{}) interface{} { 17 | return func() {} 18 | })) 19 | assert.Error(t, SetFunc("error2", func(self1 *sample, self2 *sample) interface{} { 20 | return func() {} 21 | })) 22 | } 23 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/2rebi/golang-default 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/davecgh/go-spew v1.1.1 // indirect 7 | github.com/stretchr/testify v1.7.0 8 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 9 | ) 10 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= 8 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 9 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 10 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 11 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 12 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 13 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 14 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 15 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 16 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 17 | -------------------------------------------------------------------------------- /initializer.go: -------------------------------------------------------------------------------- 1 | package def 2 | 3 | type Initializer interface { 4 | Init() 5 | } 6 | -------------------------------------------------------------------------------- /new.go: -------------------------------------------------------------------------------- 1 | package def 2 | 3 | import "reflect" 4 | 5 | func New(i interface{}) (interface{}, error) { 6 | ref := reflect.New(reflect.TypeOf(i)) 7 | defer callInit(ref) 8 | if err := initStruct(ref.Elem(), maybeInit, make(map[reflect.Type]bool)); err != nil { 9 | return nil, err 10 | } 11 | 12 | return ref.Interface(), nil 13 | } 14 | 15 | func MustNew(i interface{}) interface{} { 16 | ret, err := New(i) 17 | if err != nil { 18 | panic(err) 19 | } 20 | 21 | return ret 22 | } 23 | 24 | func JustNew(i interface{}) (interface{}, error) { 25 | ref := reflect.New(reflect.TypeOf(i)) 26 | defer callInit(ref) 27 | err := initStruct(ref.Elem(), justInit, make(map[reflect.Type]bool)) 28 | return ref.Interface(), err 29 | } 30 | -------------------------------------------------------------------------------- /new_test.go: -------------------------------------------------------------------------------- 1 | package def 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | type sample struct { 10 | B bool `def:"true"` 11 | 12 | I int `def:"123321"` 13 | I8 int8 `def:"-125"` 14 | I16 int16 `def:"-31000"` 15 | I32 int32 `def:"-123"` 16 | I64 int64 `def:"-1"` 17 | 18 | Ui uint `def:"123456790"` 19 | Ui8 uint8 `def:"0b10011011"` 20 | Ui16 uint16 `def:"65000"` 21 | Ui32 uint32 `def:"0xFFFFFFFF"` 22 | Ui64 uint64 `def:"0o77777777"` 23 | 24 | F32 float32 `def:"-3.141592"` 25 | F64 float64 `def:"3.141592653589"` 26 | 27 | C64 complex64 `def:"321,123"` 28 | C128 complex128 `def:"123,321"` 29 | 30 | Str string `def:"Hello World"` 31 | 32 | 33 | Pb *bool `def:"true"` 34 | 35 | Pi *int `def:"123321"` 36 | Pi8 *int8 `def:"-125"` 37 | Pi16 *int16 `def:"-31000"` 38 | Pi32 *int32 `def:"-123"` 39 | Pi64 *int64 `def:"-1"` 40 | 41 | Pui *uint `def:"123456790"` 42 | Pui8 *uint8 `def:"0b10011011"` 43 | Pui16 *uint16 `def:"65000"` 44 | Pui32 *uint32 `def:"0xFFFFFFFF"` 45 | Pui64 *uint64 `def:"0o77777777"` 46 | 47 | Pf32 *float32 `def:"-3.141592"` 48 | Pf64 *float64 `def:"3.141592653589"` 49 | 50 | Pc64 *complex64 `def:"321,123"` 51 | Pc128 *complex128 `def:"123,321"` 52 | 53 | Pstr *string `def:"Hello World"` 54 | 55 | Pnull *int `def:"-"` 56 | Pnil *int `def:"-"` 57 | 58 | ArrInt [3]int `def:"[1,2,3]"` 59 | SliInt []int `def:"[1,2,3,4,5,6,7,8,9,10]"` 60 | 61 | ChanInt chan int `def:"0"` 62 | 63 | Map map[string]int `def:"{\"math\":100,\"english\":30,\"some\":999}"` 64 | 65 | Time time.Time `def:"now"` 66 | After1H time.Time `def:"+1h"` 67 | Before1H time.Time `def:"-1h"` 68 | } 69 | 70 | type nestedSample struct { 71 | Name string `def:"this is nested sample"` 72 | Sample sample `def:"dive"` 73 | Psample *sample `def:"dive"` 74 | } 75 | 76 | type jsonSample struct { 77 | Name string `def:"this is json struct sample"` 78 | 79 | Json nestedJsonSample `def:"{\"age\":25,\"name\":\"rebirth lee\"}"` 80 | Pjson *nestedJsonSample `def:"{\"age\":52,\"name\":\"lee rebirth\"}"` 81 | } 82 | 83 | type nestedJsonSample struct { 84 | Age int `json:"age"` 85 | Name string `json:"name"` 86 | } 87 | 88 | type cycleErrorSample struct { 89 | Name string `def:"this is cycle sample"` 90 | Cycle *cycleErrorSample `def:"dive"` 91 | } 92 | 93 | type boolErrorSample struct { 94 | Bool bool `def:"fail parse"` 95 | } 96 | 97 | type intErrorSample struct { 98 | Number int `def:"fail parse"` 99 | } 100 | 101 | type uintErrorSample struct { 102 | Number uint `def:"-1"` 103 | } 104 | 105 | type floatErrorSample struct { 106 | Number float64 `def:"fail parse"` 107 | } 108 | 109 | type complexErrorSample struct { 110 | Number complex128 `def:"1,2,3,4,5,6"` 111 | } 112 | 113 | type complexFailParseError1Sample struct { 114 | Number complex128 `def:"fail parse,321"` 115 | } 116 | 117 | type complexFailParseError2Sample struct { 118 | Number complex128 `def:"123,fail parse"` 119 | } 120 | 121 | type chanErrorSample struct { 122 | Chan chan int `def:"-1"` 123 | } 124 | 125 | type chanFailParseErrorSample struct { 126 | Chan chan int `def:"fail parse"` 127 | } 128 | 129 | 130 | func TestNew(t *testing.T) { 131 | iface, err := New(sample{}) 132 | if assert.NoError(t, err) { 133 | sample, ok := iface.(*sample) 134 | if assert.True(t, ok) && assert.NotNil(t, sample) { 135 | checkSample(t, sample) 136 | } 137 | } 138 | 139 | 140 | iface, err = New(nestedSample{}) 141 | if assert.NoError(t, err) { 142 | sample, ok := iface.(*nestedSample) 143 | if assert.True(t, ok) && assert.NotNil(t, sample) { 144 | assert.Equal(t, sample.Name, "this is nested sample") 145 | if assert.NotNil(t, sample.Psample) { 146 | checkSample(t, sample.Psample) 147 | } 148 | checkSample(t, &sample.Sample) 149 | } 150 | } 151 | 152 | iface, err = New(jsonSample{}) 153 | if assert.NoError(t, err) { 154 | sample, ok := iface.(*jsonSample) 155 | if assert.True(t, ok) && assert.NotNil(t, sample) { 156 | assert.Equal(t, sample.Name, "this is json struct sample") 157 | 158 | assert.Equal(t, sample.Json.Name, "rebirth lee") 159 | assert.Equal(t, sample.Json.Age, 25) 160 | 161 | if assert.NotNil(t, sample.Pjson) { 162 | assert.Equal(t, sample.Pjson.Name, "lee rebirth") 163 | assert.Equal(t, sample.Pjson.Age, 52) 164 | } 165 | } 166 | } 167 | 168 | errorCheckList := []interface{}{ 169 | cycleErrorSample{}, 170 | boolErrorSample{}, 171 | intErrorSample{}, 172 | uintErrorSample{}, 173 | floatErrorSample{}, 174 | complexErrorSample{}, 175 | complexFailParseError1Sample{}, 176 | complexFailParseError2Sample{}, 177 | chanErrorSample{}, 178 | chanFailParseErrorSample{}, 179 | } 180 | 181 | for i := range errorCheckList { 182 | iface, err = New(errorCheckList[i]) 183 | assert.Nil(t, iface) 184 | assert.Error(t, err) 185 | } 186 | } 187 | 188 | func TestMustNew(t *testing.T) { 189 | 190 | { 191 | sample := MustNew(sample{}).(*sample) 192 | if assert.NotNil(t, sample) { 193 | checkSample(t, sample) 194 | } 195 | } 196 | 197 | { 198 | sample := MustNew(nestedSample{}).(*nestedSample) 199 | if assert.NotNil(t, sample) { 200 | assert.Equal(t, sample.Name, "this is nested sample") 201 | if assert.NotNil(t, sample.Psample) { 202 | checkSample(t, sample.Psample) 203 | } 204 | checkSample(t, &sample.Sample) 205 | } 206 | } 207 | 208 | { 209 | sample := MustNew(jsonSample{}).(*jsonSample) 210 | if assert.NotNil(t, sample) { 211 | assert.Equal(t, sample.Name, "this is json struct sample") 212 | 213 | assert.Equal(t, sample.Json.Name, "rebirth lee") 214 | assert.Equal(t, sample.Json.Age, 25) 215 | 216 | if assert.NotNil(t, sample.Pjson) { 217 | assert.Equal(t, sample.Pjson.Name, "lee rebirth") 218 | assert.Equal(t, sample.Pjson.Age, 52) 219 | } 220 | } 221 | } 222 | 223 | errorCheckList := []interface{}{ 224 | cycleErrorSample{}, 225 | boolErrorSample{}, 226 | intErrorSample{}, 227 | uintErrorSample{}, 228 | floatErrorSample{}, 229 | complexErrorSample{}, 230 | complexFailParseError1Sample{}, 231 | complexFailParseError2Sample{}, 232 | chanErrorSample{}, 233 | chanFailParseErrorSample{}, 234 | } 235 | 236 | for i := range errorCheckList { 237 | assert.Panics(t, func() { 238 | MustNew(errorCheckList[i]) 239 | }) 240 | } 241 | } 242 | 243 | func TestJustNew(t *testing.T) { 244 | iface, err := JustNew(sample{}) 245 | if assert.NoError(t, err) { 246 | sample, ok := iface.(*sample) 247 | if assert.True(t, ok) && assert.NotNil(t, sample) { 248 | checkSample(t, sample) 249 | } 250 | } 251 | 252 | 253 | iface, err = JustNew(nestedSample{}) 254 | if assert.NoError(t, err) { 255 | sample, ok := iface.(*nestedSample) 256 | if assert.True(t, ok) && assert.NotNil(t, sample) { 257 | assert.Equal(t, sample.Name, "this is nested sample") 258 | if assert.NotNil(t, sample.Psample) { 259 | checkSample(t, sample.Psample) 260 | } 261 | checkSample(t, &sample.Sample) 262 | } 263 | } 264 | 265 | iface, err = JustNew(jsonSample{}) 266 | if assert.NoError(t, err) { 267 | sample, ok := iface.(*jsonSample) 268 | if assert.True(t, ok) && assert.NotNil(t, sample) { 269 | assert.Equal(t, sample.Name, "this is json struct sample") 270 | 271 | assert.Equal(t, sample.Json.Name, "rebirth lee") 272 | assert.Equal(t, sample.Json.Age, 25) 273 | 274 | if assert.NotNil(t, sample.Pjson) { 275 | assert.Equal(t, sample.Pjson.Name, "lee rebirth") 276 | assert.Equal(t, sample.Pjson.Age, 52) 277 | } 278 | } 279 | } 280 | 281 | errorCheckList := []interface{}{ 282 | cycleErrorSample{}, 283 | boolErrorSample{}, 284 | intErrorSample{}, 285 | uintErrorSample{}, 286 | floatErrorSample{}, 287 | complexErrorSample{}, 288 | complexFailParseError1Sample{}, 289 | complexFailParseError2Sample{}, 290 | chanErrorSample{}, 291 | chanFailParseErrorSample{}, 292 | } 293 | 294 | for i := range errorCheckList { 295 | iface, err = JustNew(errorCheckList[i]) 296 | assert.NotNil(t, iface) 297 | assert.Error(t, err) 298 | } 299 | } 300 | 301 | func checkSample(t *testing.T, sample *sample) { 302 | assert.True(t, sample.B) 303 | 304 | assert.Equal(t, sample.I, 123321) 305 | assert.Equal(t, sample.I8, int8(-125)) 306 | assert.Equal(t, sample.I16, int16(-31000)) 307 | assert.Equal(t, sample.I32, int32(-123)) 308 | assert.Equal(t, sample.I64, int64(-1)) 309 | 310 | assert.Equal(t, sample.Ui, uint(123456790)) 311 | assert.Equal(t, sample.Ui8, uint8(0b10011011)) 312 | assert.Equal(t, sample.Ui16, uint16(65000)) 313 | assert.Equal(t, sample.Ui32, uint32(0xFFFFFFFF)) 314 | assert.Equal(t, sample.Ui64, uint64(0o77777777)) 315 | 316 | assert.Equal(t, sample.F32, float32(-3.141592)) 317 | assert.Equal(t, sample.F64, 3.141592653589) 318 | 319 | assert.Equal(t, sample.C64, complex64(321+123i)) 320 | assert.Equal(t, sample.C128, 123+321i) 321 | 322 | assert.Equal(t, sample.Str, "Hello World") 323 | 324 | //pointer 325 | assert.NotNil(t, sample.Pb) 326 | 327 | assert.NotNil(t, sample.Pi) 328 | assert.NotNil(t, sample.Pi8) 329 | assert.NotNil(t, sample.Pi16) 330 | assert.NotNil(t, sample.Pi32) 331 | assert.NotNil(t, sample.Pi64) 332 | 333 | assert.NotNil(t, sample.Pui) 334 | assert.NotNil(t, sample.Pui8) 335 | assert.NotNil(t, sample.Pui16) 336 | assert.NotNil(t, sample.Pui32) 337 | assert.NotNil(t, sample.Pui64) 338 | 339 | assert.NotNil(t, sample.Pf32) 340 | assert.NotNil(t, sample.Pf64) 341 | 342 | assert.NotNil(t, sample.Pc64) 343 | assert.NotNil(t, sample.Pc128) 344 | 345 | assert.NotNil(t, sample.Pstr) 346 | 347 | assert.Nil(t, sample.Pnull) 348 | assert.Nil(t, sample.Pnil) 349 | 350 | // equal pointer value 351 | assert.Equal(t, sample.B, *sample.Pb) 352 | 353 | assert.Equal(t, sample.I, *sample.Pi) 354 | assert.Equal(t, sample.I8, *sample.Pi8) 355 | assert.Equal(t, sample.I16, *sample.Pi16) 356 | assert.Equal(t, sample.I32, *sample.Pi32) 357 | assert.Equal(t, sample.I64, *sample.Pi64) 358 | 359 | assert.Equal(t, sample.Ui, *sample.Pui) 360 | assert.Equal(t, sample.Ui8, *sample.Pui8) 361 | assert.Equal(t, sample.Ui16, *sample.Pui16) 362 | assert.Equal(t, sample.Ui32, *sample.Pui32) 363 | assert.Equal(t, sample.Ui64, *sample.Pui64) 364 | 365 | assert.Equal(t, sample.F32, *sample.Pf32) 366 | assert.Equal(t, sample.F64, *sample.Pf64) 367 | 368 | assert.Equal(t, sample.C64, *sample.Pc64) 369 | assert.Equal(t, sample.C128, *sample.Pc128) 370 | 371 | assert.Equal(t, sample.Str, *sample.Pstr) 372 | 373 | // special type 374 | assert.NotNil(t, sample.ArrInt) 375 | assert.Equal(t, sample.ArrInt, [3]int{1,2,3}) 376 | 377 | assert.NotNil(t, sample.SliInt) 378 | assert.Equal(t, sample.SliInt, []int{1,2,3,4,5,6,7,8,9,10}) 379 | 380 | assert.NotNil(t, sample.ChanInt) 381 | assert.Len(t, sample.ChanInt, 0) 382 | 383 | assert.NotNil(t, sample.Map) 384 | assert.Equal(t, sample.Map, map[string]int{ 385 | "math": 100, 386 | "english": 30, 387 | "some": 999, 388 | }) 389 | 390 | assert.NotZero(t, sample.Time) 391 | assert.NotZero(t, sample.After1H) 392 | assert.NotZero(t, sample.Before1H) 393 | 394 | assert.True(t, sample.Time.After(sample.Before1H)) 395 | assert.True(t, sample.Time.Before(sample.After1H)) 396 | } -------------------------------------------------------------------------------- /util.go: -------------------------------------------------------------------------------- 1 | package def 2 | 3 | import ( 4 | "strconv" 5 | "strings" 6 | ) 7 | 8 | func getBaseValue(val string) (string, int, int) { 9 | base := 10 10 | if strings.HasPrefix(val, "0x") { 11 | base = 16 12 | val = strings.TrimPrefix(val, "0x") 13 | } else if strings.HasPrefix(val, "0o") { 14 | base = 8 15 | val = strings.TrimPrefix(val, "0o") 16 | } else if strings.HasPrefix(val, "0b") { 17 | base = 2 18 | val = strings.TrimPrefix(val, "0b") 19 | } 20 | 21 | return val, base, 0 22 | } 23 | 24 | func getStringToComplex(r, i string) (complex128, error) { 25 | nR, err := strconv.ParseFloat(r, 0) 26 | if err != nil { 27 | return 0, err 28 | } 29 | nI, err := strconv.ParseFloat(i, 0) 30 | if err != nil { 31 | return 0, err 32 | } 33 | 34 | return complex(nR, nI), nil 35 | } -------------------------------------------------------------------------------- /util_test.go: -------------------------------------------------------------------------------- 1 | package def 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "testing" 6 | ) 7 | 8 | func Test_getBaseValue(t *testing.T) { 9 | num, base, bit := getBaseValue("0xff") 10 | assert.Equal(t, num, "ff") 11 | assert.Equal(t, base, 16) 12 | assert.Equal(t, bit, 0) 13 | 14 | num, base, bit = getBaseValue("0o77") 15 | assert.Equal(t, num, "77") 16 | assert.Equal(t, base, 8) 17 | assert.Equal(t, bit, 0) 18 | 19 | num, base, bit = getBaseValue("0b11") 20 | assert.Equal(t, num, "11") 21 | assert.Equal(t, base, 2) 22 | assert.Equal(t, bit, 0) 23 | 24 | 25 | num, base, bit = getBaseValue("3000") 26 | assert.Equal(t, num, "3000") 27 | assert.Equal(t, base, 10) 28 | assert.Equal(t, bit, 0) 29 | } 30 | 31 | func Test_getStringToComplex(t *testing.T) { 32 | com, err := getStringToComplex("123", "321") 33 | if assert.NoError(t, err) { 34 | assert.Equal(t, com, 123+321i) 35 | } 36 | 37 | com, err = getStringToComplex("123", "") 38 | if assert.Error(t, err) { 39 | assert.Equal(t, com, complex128(0)) 40 | } 41 | 42 | com, err = getStringToComplex("", "321") 43 | if assert.Error(t, err) { 44 | assert.Equal(t, com, complex128(0)) 45 | } 46 | } --------------------------------------------------------------------------------