github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/reflector/README.md (about)

     1  # Golang reflector
     2  
     3  First, don't use reflection if you don't have to.
     4  
     5  But if you really have to... This library offers a simplified Golang reflection abstraction.
     6  
     7  ## Getting and setting fields
     8  
     9  Let's suppose we have structs like:
    10  
    11      type Address struct {
    12          Street string `tag:"be" tag2:"1,2,3"`
    13          Number int    `tag:"bi"`
    14      }
    15  
    16      type Person struct {
    17          Name string `tag:"bu"`
    18          Address
    19      }
    20  
    21      func (p Person) Hi(name string) string {
    22          return fmt.Sprintf("Hi %s my name is %s", name, p.Name)
    23      }
    24  
    25  Initialize the **reflector**'s object wrapper:
    26  
    27      import "github.com/tkrajina/go-reflector/reflector"
    28  
    29  	p := Person{}
    30  	obj := reflector.New(p)
    31  
    32  Check if a field is valid:
    33  
    34      obj.Field("Name").IsValid()
    35  
    36  Get field value:
    37  
    38      val, err := obj.Field("Name").Get()
    39  
    40  Set field value:
    41  
    42  	p := Person{}
    43  	obj := reflector.New(&p)
    44      err := obj.Field("Name").Set("Something")
    45  
    46  Don't forget to use a pointer in `New()`, otherwise setters won't work. Field "settability" can be checked by using `field.IsSettable()`.
    47  
    48  ## Tags
    49  
    50  Get a tag:
    51  
    52      jsonTag := obj.Field("Name").Tag("json")
    53  
    54  Get tag values array (exploded with "," as a delimiter):
    55  
    56      jsonTag := obj.Field("Name").TagExpanded("json")
    57  
    58  Or get a map with all field tags:
    59  
    60      fieldTagsMap := obj.Field("Name").Tags()
    61  
    62  ## Listing fields
    63  
    64  There are three ways to list fields:
    65  
    66   * List all fields: This will include anonymous structs **and** fields declared in  anonymous structs (`Name`, `Address`, `Street`, `Number`).
    67   * List flattened fields: Includes fields declared in anonymous structs **without**  anonymous structs (`Name`, `Street`, `Number`).
    68   * List nonflattened fields: Includes anonymous structs **without** their fields (`Name`, `Address`). This is the way fields are actually declared in the code.
    69  
    70  Depending on which listing you want, you can use:
    71  
    72      fields := obj.FieldsAll()
    73      fields := obj.FieldsFlattened()
    74      fields := obj.Fields()
    75  
    76  You can only get the list of anonymous fields with `obj.FieldsAnonymous()`.
    77  
    78  Be aware that because of anonymous structs, some field names can be returned twice!
    79  In most cases this is not a desired situation, but you can use **reflector** to detect such situations in your code:
    80  
    81      doubleDeclaredFields := obj.FindDoubleFields()
    82      if len(doubleDeclaredFields) > 0 {
    83          fmt.Println("Detected multiple fields with same name:", doubleDeclaredFields)
    84      }
    85  
    86  The field listing will contain both exported and unexported fields. Unexported fields are not gettable/settable, but their tags are readable.
    87  
    88  ## Calling methods
    89  
    90  	obj := reflector.New(&Person{})
    91      resp, err := obj.Method("Hi").Call("John", "Smith")
    92  
    93  The `err` is not `nil` only if something was wrong with the method (for example invalid method name, or wrong argument number/types), not with the actual method call.
    94  If the call finished, `err` will be `nil`.
    95  If the method call returned an error, you can check it with:
    96  
    97      if resp.IsError() {
    98          fmt.Println("Got an error:", resp.Error.Error())
    99      } else {
   100          fmt.Println("Method call response:", resp.Result)
   101      }
   102  
   103  ## Listing methods
   104  
   105      for _, method := range obj.Methods() {
   106          fmt.Println("Method", method.Name(), "with input types", method.InTypes(), "and output types", method.OutTypes())
   107      }
   108  
   109  ## Getting length, getting and setting slice/array/string/map elements
   110  
   111  Map:
   112  
   113      m := map[string]interface{}{"aaa", 17}
   114      o := reflector.New(m)
   115      fmt.Println("Length", o.Len())
   116      val, found := o.GetByKey("aaa")
   117      o.SetByKey("bbb", "new value")
   118      fmt.Println("keys:", o.Keys())
   119  
   120  Slice, string:
   121  
   122      l := []int{1, 2, 3}
   123      o := reflector.New(o)
   124      fmt.Println("Length", o.Len())
   125      val, found := o.GetByIndex(0)
   126      o.SetByIndex(0, 19)
   127  
   128  ## Performance
   129  
   130  When reflecting the same type multiple times, **reflector** will cache as much reflection metadata as possible **only once** and use that in future.
   131  
   132  If you make any changes to the library, run `make test-performance` to check performance improvement/deterioration before/after your change.
   133  
   134      $ make test-performance
   135      N=1000000 go test -v ./... -run=TestPerformance
   136      === RUN   TestPerformance
   137      WITH REFLECTION
   138          n= 1000000
   139          started: 2016-05-25 08:35:15.5258
   140          ended: 2016-05-25 08:35:19.5258
   141          duration: 4.269112s
   142      --- PASS: TestPerformance (4.27s)
   143      === RUN   TestPerformancePlain
   144      WITHOUT REFLECTION
   145          n= 1000000
   146          started: 2016-05-25 08:35:19.5258
   147          ended: 2016-05-25 08:35:19.5258
   148          duration: 0.005237s
   149      --- PASS: TestPerformancePlain (0.01s)
   150      PASS
   151      ok      github.com/tkrajina/go-reflector/reflector      4.285s
   152  
   153  Keep those numbers in mind before deciding to use reflection :)
   154  
   155  License
   156  -------
   157  
   158  **Reflector** is licensed under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)