github.com/wangyougui/gf/v2@v2.6.5/util/gconv/gconv_struct.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/wangyougui/gf. 6 7 package gconv 8 9 import ( 10 "reflect" 11 "strings" 12 13 "github.com/wangyougui/gf/v2/errors/gcode" 14 "github.com/wangyougui/gf/v2/errors/gerror" 15 "github.com/wangyougui/gf/v2/internal/empty" 16 "github.com/wangyougui/gf/v2/internal/json" 17 "github.com/wangyougui/gf/v2/internal/utils" 18 "github.com/wangyougui/gf/v2/os/gstructs" 19 "github.com/wangyougui/gf/v2/util/gtag" 20 ) 21 22 // Struct maps the params key-value pairs to the corresponding struct object's attributes. 23 // The third parameter `mapping` is unnecessary, indicating the mapping rules between the 24 // custom key name and the attribute name(case-sensitive). 25 // 26 // Note: 27 // 1. The `params` can be any type of map/struct, usually a map. 28 // 2. The `pointer` should be type of *struct/**struct, which is a pointer to struct object 29 // or struct pointer. 30 // 3. Only the public attributes of struct object can be mapped. 31 // 4. If `params` is a map, the key of the map `params` can be lowercase. 32 // It will automatically convert the first letter of the key to uppercase 33 // in mapping procedure to do the matching. 34 // It ignores the map key, if it does not match. 35 func Struct(params interface{}, pointer interface{}, paramKeyToAttrMap ...map[string]string) (err error) { 36 return Scan(params, pointer, paramKeyToAttrMap...) 37 } 38 39 // StructTag acts as Struct but also with support for priority tag feature, which retrieves the 40 // specified tags for `params` key-value items to struct attribute names mapping. 41 // The parameter `priorityTag` supports multiple tags that can be joined with char ','. 42 func StructTag(params interface{}, pointer interface{}, priorityTag string) (err error) { 43 return doStruct(params, pointer, nil, priorityTag) 44 } 45 46 // doStruct is the core internal converting function for any data to struct. 47 func doStruct( 48 params interface{}, pointer interface{}, paramKeyToAttrMap map[string]string, priorityTag string, 49 ) (err error) { 50 if params == nil { 51 // If `params` is nil, no conversion. 52 return nil 53 } 54 if pointer == nil { 55 return gerror.NewCode(gcode.CodeInvalidParameter, "object pointer cannot be nil") 56 } 57 58 // JSON content converting. 59 ok, err := doConvertWithJsonCheck(params, pointer) 60 if err != nil { 61 return err 62 } 63 if ok { 64 return nil 65 } 66 67 defer func() { 68 // Catch the panic, especially the reflection operation panics. 69 if exception := recover(); exception != nil { 70 if v, ok := exception.(error); ok && gerror.HasStack(v) { 71 err = v 72 } else { 73 err = gerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, "%+v", exception) 74 } 75 } 76 }() 77 78 var ( 79 paramsReflectValue reflect.Value 80 paramsInterface interface{} // DO NOT use `params` directly as it might be type `reflect.Value` 81 pointerReflectValue reflect.Value 82 pointerReflectKind reflect.Kind 83 pointerElemReflectValue reflect.Value // The pointed element. 84 ) 85 if v, ok := params.(reflect.Value); ok { 86 paramsReflectValue = v 87 } else { 88 paramsReflectValue = reflect.ValueOf(params) 89 } 90 paramsInterface = paramsReflectValue.Interface() 91 if v, ok := pointer.(reflect.Value); ok { 92 pointerReflectValue = v 93 pointerElemReflectValue = v 94 } else { 95 pointerReflectValue = reflect.ValueOf(pointer) 96 pointerReflectKind = pointerReflectValue.Kind() 97 if pointerReflectKind != reflect.Ptr { 98 return gerror.NewCodef( 99 gcode.CodeInvalidParameter, 100 "destination pointer should be type of '*struct', but got '%v'", 101 pointerReflectKind, 102 ) 103 } 104 // Using IsNil on reflect.Ptr variable is OK. 105 if !pointerReflectValue.IsValid() || pointerReflectValue.IsNil() { 106 return gerror.NewCode( 107 gcode.CodeInvalidParameter, 108 "destination pointer cannot be nil", 109 ) 110 } 111 pointerElemReflectValue = pointerReflectValue.Elem() 112 } 113 114 // If `params` and `pointer` are the same type, the do directly assignment. 115 // For performance enhancement purpose. 116 if ok = doConvertWithTypeCheck(paramsReflectValue, pointerElemReflectValue); ok { 117 return nil 118 } 119 120 // custom convert. 121 if ok, err = callCustomConverter(paramsReflectValue, pointerReflectValue); ok { 122 return err 123 } 124 125 // Normal unmarshalling interfaces checks. 126 if ok, err = bindVarToReflectValueWithInterfaceCheck(pointerReflectValue, paramsInterface); ok { 127 return err 128 } 129 130 // It automatically creates struct object if necessary. 131 // For example, if `pointer` is **User, then `elem` is *User, which is a pointer to User. 132 if pointerElemReflectValue.Kind() == reflect.Ptr { 133 if !pointerElemReflectValue.IsValid() || pointerElemReflectValue.IsNil() { 134 e := reflect.New(pointerElemReflectValue.Type().Elem()) 135 pointerElemReflectValue.Set(e) 136 defer func() { 137 if err != nil { 138 // If it is converted failed, it reset the `pointer` to nil. 139 pointerReflectValue.Elem().Set(reflect.Zero(pointerReflectValue.Type().Elem())) 140 } 141 }() 142 } 143 // if v, ok := pointerElemReflectValue.Interface().(iUnmarshalValue); ok { 144 // return v.UnmarshalValue(params) 145 // } 146 // Note that it's `pointerElemReflectValue` here not `pointerReflectValue`. 147 if ok, err := bindVarToReflectValueWithInterfaceCheck(pointerElemReflectValue, paramsInterface); ok { 148 return err 149 } 150 // Retrieve its element, may be struct at last. 151 pointerElemReflectValue = pointerElemReflectValue.Elem() 152 } 153 154 // paramsMap is the map[string]interface{} type variable for params. 155 // DO NOT use MapDeep here. 156 paramsMap := doMapConvert(paramsInterface, recursiveTypeAuto, true) 157 if paramsMap == nil { 158 return gerror.NewCodef( 159 gcode.CodeInvalidParameter, 160 `convert params from "%#v" to "map[string]interface{}" failed`, 161 params, 162 ) 163 } 164 165 // Nothing to be done as the parameters are empty. 166 if len(paramsMap) == 0 { 167 return nil 168 } 169 170 // It only performs one converting to the same attribute. 171 // doneMap is used to check repeated converting, its key is the real attribute name 172 // of the struct. 173 doneMap := make(map[string]struct{}) 174 175 // The key of the attrMap is the attribute name of the struct, 176 // and the value is its replaced name for later comparison to improve performance. 177 var ( 178 tempName string 179 elemFieldType reflect.StructField 180 elemFieldValue reflect.Value 181 elemType = pointerElemReflectValue.Type() 182 // Attribute name to its symbols-removed name, 183 // in order to quick index and comparison in following logic. 184 attrToCheckNameMap = make(map[string]string) 185 ) 186 for i := 0; i < pointerElemReflectValue.NumField(); i++ { 187 elemFieldType = elemType.Field(i) 188 // Only do converting to public attributes. 189 if !utils.IsLetterUpper(elemFieldType.Name[0]) { 190 continue 191 } 192 // Maybe it's struct/*struct embedded. 193 if elemFieldType.Anonymous { 194 elemFieldValue = pointerElemReflectValue.Field(i) 195 // Ignore the interface attribute if it's nil. 196 if elemFieldValue.Kind() == reflect.Interface { 197 elemFieldValue = elemFieldValue.Elem() 198 if !elemFieldValue.IsValid() { 199 continue 200 } 201 } 202 if err = doStruct(paramsMap, elemFieldValue, paramKeyToAttrMap, priorityTag); err != nil { 203 return err 204 } 205 } else { 206 tempName = elemFieldType.Name 207 attrToCheckNameMap[tempName] = utils.RemoveSymbols(tempName) 208 } 209 } 210 if len(attrToCheckNameMap) == 0 { 211 return nil 212 } 213 214 // The key of the `attrToTagCheckNameMap` is the attribute name of the struct, 215 // and the value is its replaced tag name for later comparison to improve performance. 216 var ( 217 attrToTagCheckNameMap = make(map[string]string) 218 priorityTagArray []string 219 ) 220 if priorityTag != "" { 221 priorityTagArray = append(utils.SplitAndTrim(priorityTag, ","), gtag.StructTagPriority...) 222 } else { 223 priorityTagArray = gtag.StructTagPriority 224 } 225 tagToAttrNameMap, err := gstructs.TagMapName(pointerElemReflectValue, priorityTagArray) 226 if err != nil { 227 return err 228 } 229 for tagName, attributeName := range tagToAttrNameMap { 230 // If there's something else in the tag string, 231 // it uses the first part which is split using char ','. 232 // Eg: 233 // orm:"id, priority" 234 // orm:"name, with:uid=id" 235 attrToTagCheckNameMap[attributeName] = utils.RemoveSymbols(strings.Split(tagName, ",")[0]) 236 // If tag and attribute values both exist in `paramsMap`, 237 // it then uses the tag value overwriting the attribute value in `paramsMap`. 238 if paramsMap[tagName] != nil && paramsMap[attributeName] != nil { 239 paramsMap[attributeName] = paramsMap[tagName] 240 } 241 } 242 243 // To convert value base on custom parameter key to attribute name map. 244 err = doStructBaseOnParamKeyToAttrMap( 245 pointerElemReflectValue, 246 paramsMap, 247 paramKeyToAttrMap, 248 doneMap, 249 ) 250 if err != nil { 251 return err 252 } 253 // Already done all attributes value assignment nothing to do next. 254 if len(doneMap) == len(attrToCheckNameMap) { 255 return nil 256 } 257 258 // To convert value base on precise attribute name. 259 err = doStructBaseOnAttribute( 260 pointerElemReflectValue, 261 paramsMap, 262 paramKeyToAttrMap, 263 doneMap, 264 attrToCheckNameMap, 265 ) 266 if err != nil { 267 return err 268 } 269 // Already done all attributes value assignment nothing to do next. 270 if len(doneMap) == len(attrToCheckNameMap) { 271 return nil 272 } 273 274 // To convert value base on parameter map. 275 err = doStructBaseOnParamMap( 276 pointerElemReflectValue, 277 paramsMap, 278 paramKeyToAttrMap, 279 doneMap, 280 attrToCheckNameMap, 281 attrToTagCheckNameMap, 282 tagToAttrNameMap, 283 ) 284 if err != nil { 285 return err 286 } 287 return nil 288 } 289 290 func doStructBaseOnParamKeyToAttrMap( 291 pointerElemReflectValue reflect.Value, 292 paramsMap map[string]interface{}, 293 paramKeyToAttrMap map[string]string, 294 doneAttrMap map[string]struct{}, 295 ) error { 296 if len(paramKeyToAttrMap) == 0 { 297 return nil 298 } 299 for paramKey, attrName := range paramKeyToAttrMap { 300 paramValue, ok := paramsMap[paramKey] 301 if !ok { 302 continue 303 } 304 // If the attribute name is already checked converting, then skip it. 305 if _, ok = doneAttrMap[attrName]; ok { 306 continue 307 } 308 // Mark it done. 309 doneAttrMap[attrName] = struct{}{} 310 if err := bindVarToStructAttr( 311 pointerElemReflectValue, attrName, paramValue, paramKeyToAttrMap, 312 ); err != nil { 313 return err 314 } 315 } 316 return nil 317 } 318 319 func doStructBaseOnAttribute( 320 pointerElemReflectValue reflect.Value, 321 paramsMap map[string]interface{}, 322 paramKeyToAttrMap map[string]string, 323 doneAttrMap map[string]struct{}, 324 attrToCheckNameMap map[string]string, 325 ) error { 326 var customMappingAttrMap = make(map[string]struct{}) 327 if len(paramKeyToAttrMap) > 0 { 328 // It ignores the attribute names if it is specified in the `paramKeyToAttrMap`. 329 for paramName := range paramsMap { 330 if passedAttrKey, ok := paramKeyToAttrMap[paramName]; ok { 331 customMappingAttrMap[passedAttrKey] = struct{}{} 332 } 333 } 334 } 335 for attrName := range attrToCheckNameMap { 336 // The value by precise attribute name. 337 paramValue, ok := paramsMap[attrName] 338 if !ok { 339 continue 340 } 341 // If the attribute name is in custom paramKeyToAttrMap, it then ignores this converting. 342 if _, ok = customMappingAttrMap[attrName]; ok { 343 continue 344 } 345 // If the attribute name is already checked converting, then skip it. 346 if _, ok = doneAttrMap[attrName]; ok { 347 continue 348 } 349 // Mark it done. 350 doneAttrMap[attrName] = struct{}{} 351 if err := bindVarToStructAttr( 352 pointerElemReflectValue, attrName, paramValue, paramKeyToAttrMap, 353 ); err != nil { 354 return err 355 } 356 } 357 return nil 358 } 359 360 func doStructBaseOnParamMap( 361 pointerElemReflectValue reflect.Value, 362 paramsMap map[string]interface{}, 363 paramKeyToAttrMap map[string]string, 364 doneAttrMap map[string]struct{}, 365 attrToCheckNameMap map[string]string, 366 attrToTagCheckNameMap map[string]string, 367 tagToAttrNameMap map[string]string, 368 ) error { 369 var ( 370 attrName string 371 checkName string 372 ) 373 for paramName, paramValue := range paramsMap { 374 // It firstly considers `paramName` as accurate tag name, 375 // and retrieve attribute name from `tagToAttrNameMap` . 376 attrName = tagToAttrNameMap[paramName] 377 if attrName == "" { 378 checkName = utils.RemoveSymbols(paramName) 379 // Loop to find the matched attribute name with or without 380 // string cases and chars like '-'/'_'/'.'/' '. 381 382 // Matching the parameters to struct tag names. 383 // The `attrKey` is the attribute name of the struct. 384 for attrKey, cmpKey := range attrToTagCheckNameMap { 385 if strings.EqualFold(checkName, cmpKey) { 386 attrName = attrKey 387 break 388 } 389 } 390 } 391 392 // Matching the parameters to struct attributes. 393 if attrName == "" { 394 for attrKey, cmpKey := range attrToCheckNameMap { 395 // Eg: 396 // UserName eq user_name 397 // User-Name eq username 398 // username eq userName 399 // etc. 400 if strings.EqualFold(checkName, cmpKey) { 401 attrName = attrKey 402 break 403 } 404 } 405 } 406 407 // No matching, it gives up this attribute converting. 408 if attrName == "" { 409 continue 410 } 411 // If the attribute name is already checked converting, then skip it. 412 if _, ok := doneAttrMap[attrName]; ok { 413 continue 414 } 415 // Mark it done. 416 doneAttrMap[attrName] = struct{}{} 417 if err := bindVarToStructAttr( 418 pointerElemReflectValue, attrName, paramValue, paramKeyToAttrMap, 419 ); err != nil { 420 return err 421 } 422 } 423 return nil 424 } 425 426 // bindVarToStructAttr sets value to struct object attribute by name. 427 func bindVarToStructAttr( 428 structReflectValue reflect.Value, 429 attrName string, value interface{}, paramKeyToAttrMap map[string]string, 430 ) (err error) { 431 structFieldValue := structReflectValue.FieldByName(attrName) 432 if !structFieldValue.IsValid() { 433 return nil 434 } 435 // CanSet checks whether attribute is public accessible. 436 if !structFieldValue.CanSet() { 437 return nil 438 } 439 defer func() { 440 if exception := recover(); exception != nil { 441 if err = bindVarToReflectValue(structFieldValue, value, paramKeyToAttrMap); err != nil { 442 err = gerror.Wrapf(err, `error binding value to attribute "%s"`, attrName) 443 } 444 } 445 }() 446 // Directly converting. 447 if empty.IsNil(value) { 448 structFieldValue.Set(reflect.Zero(structFieldValue.Type())) 449 } else { 450 // Try to call custom converter. 451 // Issue: https://github.com/wangyougui/gf/issues/3099 452 var ( 453 customConverterInput reflect.Value 454 ok bool 455 ) 456 if customConverterInput, ok = value.(reflect.Value); !ok { 457 customConverterInput = reflect.ValueOf(value) 458 } 459 460 if ok, err = callCustomConverter(customConverterInput, structFieldValue); ok || err != nil { 461 return 462 } 463 464 // Special handling for certain types: 465 // - Overwrite the default type converting logic of stdlib for time.Time/*time.Time. 466 var structFieldTypeName = structFieldValue.Type().String() 467 switch structFieldTypeName { 468 case "time.Time", "*time.Time": 469 doConvertWithReflectValueSet(structFieldValue, doConvertInput{ 470 FromValue: value, 471 ToTypeName: structFieldTypeName, 472 ReferValue: structFieldValue, 473 }) 474 return 475 // Hold the time zone consistent in recursive 476 // Issue: https://github.com/wangyougui/gf/issues/2980 477 case "*gtime.Time", "gtime.Time": 478 doConvertWithReflectValueSet(structFieldValue, doConvertInput{ 479 FromValue: value, 480 ToTypeName: structFieldTypeName, 481 ReferValue: structFieldValue, 482 }) 483 return 484 } 485 486 // Common interface check. 487 if ok, err = bindVarToReflectValueWithInterfaceCheck(structFieldValue, value); ok { 488 return err 489 } 490 491 // Default converting. 492 doConvertWithReflectValueSet(structFieldValue, doConvertInput{ 493 FromValue: value, 494 ToTypeName: structFieldTypeName, 495 ReferValue: structFieldValue, 496 }) 497 } 498 return nil 499 } 500 501 // bindVarToReflectValueWithInterfaceCheck does bind using common interfaces checks. 502 func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value interface{}) (bool, error) { 503 var pointer interface{} 504 if reflectValue.Kind() != reflect.Ptr && reflectValue.CanAddr() { 505 reflectValueAddr := reflectValue.Addr() 506 if reflectValueAddr.IsNil() || !reflectValueAddr.IsValid() { 507 return false, nil 508 } 509 // Not a pointer, but can token address, that makes it can be unmarshalled. 510 pointer = reflectValue.Addr().Interface() 511 } else { 512 if reflectValue.IsNil() || !reflectValue.IsValid() { 513 return false, nil 514 } 515 pointer = reflectValue.Interface() 516 } 517 // UnmarshalValue. 518 if v, ok := pointer.(iUnmarshalValue); ok { 519 return ok, v.UnmarshalValue(value) 520 } 521 // UnmarshalText. 522 if v, ok := pointer.(iUnmarshalText); ok { 523 var valueBytes []byte 524 if b, ok := value.([]byte); ok { 525 valueBytes = b 526 } else if s, ok := value.(string); ok { 527 valueBytes = []byte(s) 528 } else if f, ok := value.(iString); ok { 529 valueBytes = []byte(f.String()) 530 } 531 if len(valueBytes) > 0 { 532 return ok, v.UnmarshalText(valueBytes) 533 } 534 } 535 // UnmarshalJSON. 536 if v, ok := pointer.(iUnmarshalJSON); ok { 537 var valueBytes []byte 538 if b, ok := value.([]byte); ok { 539 valueBytes = b 540 } else if s, ok := value.(string); ok { 541 valueBytes = []byte(s) 542 } else if f, ok := value.(iString); ok { 543 valueBytes = []byte(f.String()) 544 } 545 546 if len(valueBytes) > 0 { 547 // If it is not a valid JSON string, it then adds char `"` on its both sides to make it is. 548 if !json.Valid(valueBytes) { 549 newValueBytes := make([]byte, len(valueBytes)+2) 550 newValueBytes[0] = '"' 551 newValueBytes[len(newValueBytes)-1] = '"' 552 copy(newValueBytes[1:], valueBytes) 553 valueBytes = newValueBytes 554 } 555 return ok, v.UnmarshalJSON(valueBytes) 556 } 557 } 558 if v, ok := pointer.(iSet); ok { 559 v.Set(value) 560 return ok, nil 561 } 562 return false, nil 563 } 564 565 // bindVarToReflectValue sets `value` to reflect value object `structFieldValue`. 566 func bindVarToReflectValue( 567 structFieldValue reflect.Value, value interface{}, paramKeyToAttrMap map[string]string, 568 ) (err error) { 569 // JSON content converting. 570 ok, err := doConvertWithJsonCheck(value, structFieldValue) 571 if err != nil { 572 return err 573 } 574 if ok { 575 return nil 576 } 577 578 kind := structFieldValue.Kind() 579 // Converting using `Set` interface implements, for some types. 580 switch kind { 581 case reflect.Slice, reflect.Array, reflect.Ptr, reflect.Interface: 582 if !structFieldValue.IsNil() { 583 if v, ok := structFieldValue.Interface().(iSet); ok { 584 v.Set(value) 585 return nil 586 } 587 } 588 } 589 590 // Converting using reflection by kind. 591 switch kind { 592 case reflect.Map: 593 return doMapToMap(value, structFieldValue, paramKeyToAttrMap) 594 595 case reflect.Struct: 596 // Recursively converting for struct attribute. 597 if err = doStruct(value, structFieldValue, nil, ""); err != nil { 598 // Note there's reflect conversion mechanism here. 599 structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type())) 600 } 601 602 // Note that the slice element might be type of struct, 603 // so it uses Struct function doing the converting internally. 604 case reflect.Slice, reflect.Array: 605 var ( 606 reflectArray reflect.Value 607 reflectValue = reflect.ValueOf(value) 608 ) 609 if reflectValue.Kind() == reflect.Slice || reflectValue.Kind() == reflect.Array { 610 reflectArray = reflect.MakeSlice(structFieldValue.Type(), reflectValue.Len(), reflectValue.Len()) 611 if reflectValue.Len() > 0 { 612 var ( 613 elemType = reflectArray.Index(0).Type() 614 elemTypeName string 615 converted bool 616 ) 617 for i := 0; i < reflectValue.Len(); i++ { 618 converted = false 619 elemTypeName = elemType.Name() 620 if elemTypeName == "" { 621 elemTypeName = elemType.String() 622 } 623 var elem reflect.Value 624 if elemType.Kind() == reflect.Ptr { 625 elem = reflect.New(elemType.Elem()).Elem() 626 } else { 627 elem = reflect.New(elemType).Elem() 628 } 629 if elem.Kind() == reflect.Struct { 630 if err = doStruct(reflectValue.Index(i).Interface(), elem, nil, ""); err == nil { 631 converted = true 632 } 633 } 634 if !converted { 635 doConvertWithReflectValueSet(elem, doConvertInput{ 636 FromValue: reflectValue.Index(i).Interface(), 637 ToTypeName: elemTypeName, 638 ReferValue: elem, 639 }) 640 } 641 if elemType.Kind() == reflect.Ptr { 642 // Before it sets the `elem` to array, do pointer converting if necessary. 643 elem = elem.Addr() 644 } 645 reflectArray.Index(i).Set(elem) 646 } 647 } 648 } else { 649 var ( 650 elem reflect.Value 651 elemType = structFieldValue.Type().Elem() 652 elemTypeName = elemType.Name() 653 converted bool 654 ) 655 switch reflectValue.Kind() { 656 case reflect.String: 657 // Value is empty string. 658 if reflectValue.IsZero() { 659 var elemKind = elemType.Kind() 660 // Try to find the original type kind of the slice element. 661 if elemKind == reflect.Ptr { 662 elemKind = elemType.Elem().Kind() 663 } 664 switch elemKind { 665 case reflect.String: 666 // Empty string cannot be assigned to string slice. 667 return nil 668 } 669 } 670 } 671 if elemTypeName == "" { 672 elemTypeName = elemType.String() 673 } 674 if elemType.Kind() == reflect.Ptr { 675 elem = reflect.New(elemType.Elem()).Elem() 676 } else { 677 elem = reflect.New(elemType).Elem() 678 } 679 if elem.Kind() == reflect.Struct { 680 if err = doStruct(value, elem, nil, ""); err == nil { 681 converted = true 682 } 683 } 684 if !converted { 685 doConvertWithReflectValueSet(elem, doConvertInput{ 686 FromValue: value, 687 ToTypeName: elemTypeName, 688 ReferValue: elem, 689 }) 690 } 691 if elemType.Kind() == reflect.Ptr { 692 // Before it sets the `elem` to array, do pointer converting if necessary. 693 elem = elem.Addr() 694 } 695 reflectArray = reflect.MakeSlice(structFieldValue.Type(), 1, 1) 696 reflectArray.Index(0).Set(elem) 697 } 698 structFieldValue.Set(reflectArray) 699 700 case reflect.Ptr: 701 if structFieldValue.IsNil() || structFieldValue.IsZero() { 702 // Nil or empty pointer, it creates a new one. 703 item := reflect.New(structFieldValue.Type().Elem()) 704 if ok, err = bindVarToReflectValueWithInterfaceCheck(item, value); ok { 705 structFieldValue.Set(item) 706 return err 707 } 708 elem := item.Elem() 709 if err = bindVarToReflectValue(elem, value, paramKeyToAttrMap); err == nil { 710 structFieldValue.Set(elem.Addr()) 711 } 712 } else { 713 // Not empty pointer, it assigns values to it. 714 return bindVarToReflectValue(structFieldValue.Elem(), value, paramKeyToAttrMap) 715 } 716 717 // It mainly and specially handles the interface of nil value. 718 case reflect.Interface: 719 if value == nil { 720 // Specially. 721 structFieldValue.Set(reflect.ValueOf((*interface{})(nil))) 722 } else { 723 // Note there's reflect conversion mechanism here. 724 structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type())) 725 } 726 727 default: 728 defer func() { 729 if exception := recover(); exception != nil { 730 err = gerror.NewCodef( 731 gcode.CodeInternalPanic, 732 `cannot convert value "%+v" to type "%s":%+v`, 733 value, 734 structFieldValue.Type().String(), 735 exception, 736 ) 737 } 738 }() 739 // It here uses reflect converting `value` to type of the attribute and assigns 740 // the result value to the attribute. It might fail and panic if the usual Go 741 // conversion rules do not allow conversion. 742 structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type())) 743 } 744 return nil 745 }