github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/blog/content/laws-of-reflection.article (about)

     1  The Laws of Reflection
     2  6 Sep 2011
     3  Tags: interface, reflect, type, technical
     4  
     5  Rob Pike
     6  
     7  * Introduction
     8  
     9  Reflection in computing is the ability of a program to examine its own structure, particularly through types; it's a form of metaprogramming. It's also a great source of confusion.
    10  
    11  In this article we attempt to clarify things by explaining how reflection works in Go. Each language's reflection model is different (and many languages don't support it at all), but this article is about Go, so for the rest of this article the word "reflection" should be taken to mean "reflection in Go".
    12  
    13  * Types and interfaces
    14  
    15  Because reflection builds on the type system, let's start with a refresher about types in Go.
    16  
    17  Go is statically typed. Every variable has a static type, that is, exactly one type known and fixed at compile time: `int`, `float32`, `*MyType`, `[]byte`, and so on. If we declare
    18  
    19  	type MyInt int
    20  
    21  	var i int
    22  	var j MyInt
    23  
    24  then `i` has type `int` and `j` has type `MyInt`. The variables `i` and `j` have distinct static types and, although they have the same underlying type, they cannot be assigned to one another without a conversion.
    25  
    26  One important category of type is interface types, which represent fixed sets of methods. An interface variable can store any concrete (non-interface) value as long as that value implements the interface's methods. A well-known pair of examples is `io.Reader` and `io.Writer`, the types `Reader` and `Writer` from the [[http://golang.org/pkg/io/][io package]]:
    27  
    28  	// Reader is the interface that wraps the basic Read method.
    29  	type Reader interface {
    30  	    Read(p []byte) (n int, err error)
    31  	}
    32  
    33  	// Writer is the interface that wraps the basic Write method.
    34  	type Writer interface {
    35  	    Write(p []byte) (n int, err error)
    36  	}
    37  
    38  Any type that implements a `Read` (or `Write`) method with this signature is said to implement `io.Reader` (or `io.Writer`). For the purposes of this discussion, that means that a variable of type `io.Reader` can hold any value whose type has a `Read` method:
    39  
    40  	    var r io.Reader
    41  	    r = os.Stdin
    42  	    r = bufio.NewReader(r)
    43  	    r = new(bytes.Buffer)
    44  	    // and so on
    45  
    46  It's important to be clear that whatever concrete value `r` may hold, `r`'s type is always `io.Reader`: Go is statically typed and the static type of `r` is `io.Reader`.
    47  
    48  An extremely important example of an interface type is the empty interface:
    49  
    50  	interface{}
    51  
    52  It represents the empty set of methods and is satisfied by any value at all, since any value has zero or more methods.
    53  
    54  Some people say that Go's interfaces are dynamically typed, but that is misleading. They are statically typed: a variable of interface type always has the same static type, and even though at run time the value stored in the interface variable may change type, that value will always satisfy the interface.
    55  
    56  We need to be precise about all this because reflection and interfaces are closely related.
    57  
    58  * The representation of an interface
    59  
    60  Russ Cox has written a [[http://research.swtch.com/2009/12/go-data-structures-interfaces.html][ detailed blog post]] about the representation of interface values in Go. It's not necessary to repeat the full story here, but a simplified summary is in order.
    61  
    62  A variable of interface type stores a pair: the concrete value assigned to the variable, and that value's type descriptor. To be more precise, the value is the underlying concrete data item that implements the interface and the type describes the full type of that item. For instance, after
    63  
    64  	    var r io.Reader
    65  	    tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
    66  	    if err != nil {
    67  	        return nil, err
    68  	    }
    69  	    r = tty
    70  
    71  `r` contains, schematically, the (value, type) pair, (`tty`, `*os.File`). Notice that the type `*os.File` implements methods other than `Read`; even though the interface value provides access only to the `Read` method, the value inside carries all the type information about that value. That's why we can do things like this:
    72  
    73  	    var w io.Writer
    74  	    w = r.(io.Writer)
    75  
    76  The expression in this assignment is a type assertion; what it asserts is that the item inside `r` also implements `io.Writer`, and so we can assign it to `w`. After the assignment, `w` will contain the pair (`tty`, `*os.File`). That's the same pair as was held in `r`. The static type of the interface determines what methods may be invoked with an interface variable, even though the concrete value inside may have a larger set of methods.
    77  
    78  Continuing, we can do this:
    79  
    80  	    var empty interface{}
    81  	    empty = w
    82  
    83  and our empty interface value `empty` will again contain that same pair, (`tty`, `*os.File`). That's handy: an empty interface can hold any value and contains all the information we could ever need about that value.
    84  
    85  (We don't need a type assertion here because it's known statically that `w` satisfies the empty interface. In the example where we moved a value from a `Reader` to a `Writer`, we needed to be explicit and use a type assertion because `Writer`'s methods are not a subset of `Reader`'s.)
    86  
    87  One important detail is that the pair inside an interface always has the form (value, concrete type) and cannot have the form (value, interface type). Interfaces do not hold interface values.
    88  
    89  Now we're ready to reflect.
    90  
    91  * The first law of reflection
    92  
    93  * 1. Reflection goes from interface value to reflection object.
    94  
    95  At the basic level, reflection is just a mechanism to examine the type and value pair stored inside an interface variable. To get started, there are two types we need to know about in [[http://golang.org/pkg/reflect/][package reflect]]: [[http://golang.org/pkg/reflect/#Type][Type]] and [[http://golang.org/pkg/reflect/#Value][Value]]. Those two types give access to the contents of an interface variable, and two simple functions, called `reflect.TypeOf` and `reflect.ValueOf`, retrieve `reflect.Type` and `reflect.Value` pieces out of an interface value. (Also, from the `reflect.Value` it's easy to get to the `reflect.Type`, but let's keep the `Value` and `Type` concepts separate for now.)
    96  
    97  Let's start with `TypeOf`:
    98  
    99  	package main
   100  
   101  	import (
   102  	    "fmt"
   103  	    "reflect"
   104  	)
   105  
   106  	func main() {
   107  	    var x float64 = 3.4
   108  	    fmt.Println("type:", reflect.TypeOf(x))
   109  	}
   110  
   111  This program prints
   112  
   113  	type: float64
   114  
   115  You might be wondering where the interface is here, since the program looks like it's passing the `float64` variable `x`, not an interface value, to `reflect.TypeOf`. But it's there; as [[http://golang.org/pkg/reflect/#TypeOf][godoc reports]], the signature of `reflect.TypeOf` includes an empty interface:
   116  
   117  	// TypeOf returns the reflection Type of the value in the interface{}.
   118  	func TypeOf(i interface{}) Type
   119  
   120  When we call `reflect.TypeOf(x)`, `x` is first stored in an empty interface, which is then passed as the argument; `reflect.TypeOf` unpacks that empty interface to recover the type information.
   121  
   122  The `reflect.ValueOf` function, of course, recovers the value (from here on we'll elide the boilerplate and focus just on the executable code):
   123  
   124  	    var x float64 = 3.4
   125  	    fmt.Println("value:", reflect.ValueOf(x))
   126  
   127  prints
   128  
   129  	value: <float64 Value>
   130  
   131  Both `reflect.Type` and `reflect.Value` have lots of methods to let us examine and manipulate them. One important example is that `Value` has a `Type` method that returns the `Type` of a `reflect.Value`. Another is that both `Type` and `Value` have a `Kind` method that returns a constant indicating what sort of item is stored: `Uint`, `Float64`, `Slice`, and so on. Also methods on `Value` with names like `Int` and `Float` let us grab values (as `int64` and `float64`) stored inside:
   132  
   133  	    var x float64 = 3.4
   134  	    v := reflect.ValueOf(x)
   135  	    fmt.Println("type:", v.Type())
   136  	    fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
   137  	    fmt.Println("value:", v.Float())
   138  
   139  prints
   140  
   141  	type: float64
   142  	kind is float64: true
   143  	value: 3.4
   144  
   145  There are also methods like `SetInt` and `SetFloat` but to use them we need to understand settability, the subject of the third law of reflection, discussed below.
   146  
   147  The reflection library has a couple of properties worth singling out. First, to keep the API simple, the "getter" and "setter" methods of `Value` operate on the largest type that can hold the value: `int64` for all the signed integers, for instance. That is, the `Int` method of `Value` returns an `int64` and the `SetInt` value takes an `int64`; it may be necessary to convert to the actual type involved:
   148  
   149  	    var x uint8 = 'x'
   150  	    v := reflect.ValueOf(x)
   151  	    fmt.Println("type:", v.Type())                            // uint8.
   152  	    fmt.Println("kind is uint8: ", v.Kind() == reflect.Uint8) // true.
   153  	    x = uint8(v.Uint())                                       // v.Uint returns a uint64.
   154  
   155  The second property is that the `Kind` of a reflection object describes the underlying type, not the static type. If a reflection object contains a value of a user-defined integer type, as in
   156  
   157  	    type MyInt int
   158  	    var x MyInt = 7
   159  	    v := reflect.ValueOf(x)
   160  
   161  the `Kind` of `v` is still `reflect.Int`, even though the static type of `x` is `MyInt`, not `int`. In other words, the `Kind` cannot discriminate an int from a `MyInt` even though the `Type` can.
   162  
   163  * The second law of reflection
   164  
   165  * 2. Reflection goes from reflection object to interface value.
   166  
   167  Like physical reflection, reflection in Go generates its own inverse.
   168  
   169  Given a `reflect.Value` we can recover an interface value using the `Interface` method; in effect the method packs the type and value information back into an interface representation and returns the result:
   170  
   171  	// Interface returns v's value as an interface{}.
   172  	func (v Value) Interface() interface{}
   173  
   174  As a consequence we can say
   175  
   176  	    y := v.Interface().(float64) // y will have type float64.
   177  	    fmt.Println(y)
   178  
   179  to print the `float64` value represented by the reflection object `v`.
   180  
   181  We can do even better, though. The arguments to `fmt.Println`, `fmt.Printf` and so on are all passed as empty interface values, which are then unpacked by the `fmt` package internally just as we have been doing in the previous examples. Therefore all it takes to print the contents of a `reflect.Value` correctly is to pass the result of the `Interface` method to the formatted print routine:
   182  
   183  	    fmt.Println(v.Interface())
   184  
   185  (Why not `fmt.Println(v)`? Because `v` is a `reflect.Value`; we want the concrete value it holds.) Since our value is a `float64`, we can even use a floating-point format if we want:
   186  
   187  	    fmt.Printf("value is %7.1e\n", v.Interface())
   188  
   189  and get in this case
   190  
   191  	3.4e+00
   192  
   193  Again, there's no need to type-assert the result of `v.Interface()` to `float64`; the empty interface value has the concrete value's type information inside and `Printf` will recover it.
   194  
   195  In short, the `Interface` method is the inverse of the `ValueOf` function, except that its result is always of static type `interface{}`.
   196  
   197  Reiterating: Reflection goes from interface values to reflection objects and back again.
   198  
   199  * The third law of reflection
   200  
   201  * 3. To modify a reflection object, the value must be settable.
   202  
   203  The third law is the most subtle and confusing, but it's easy enough to understand if we start from first principles.
   204  
   205  Here is some code that does not work, but is worth studying.
   206  
   207  	    var x float64 = 3.4
   208  	    v := reflect.ValueOf(x)
   209  	    v.SetFloat(7.1) // Error: will panic.
   210  
   211  If you run this code, it will panic with the cryptic message
   212  
   213  	panic: reflect.Value.SetFloat using unaddressable value
   214  
   215  The problem is not that the value `7.1` is not addressable; it's that `v` is not settable. Settability is a property of a reflection `Value`, and not all reflection `Values` have it.
   216  
   217  The `CanSet` method of `Value` reports the settability of a `Value`; in our case,
   218  
   219  	    var x float64 = 3.4
   220  	    v := reflect.ValueOf(x)
   221  	    fmt.Println("settability of v:", v.CanSet())
   222  
   223  prints
   224  
   225  	settability of v: false
   226  
   227  It is an error to call a `Set` method on an non-settable `Value`. But what is settability?
   228  
   229  Settability is a bit like addressability, but stricter. It's the property that a reflection object can modify the actual storage that was used to create the reflection object. Settability is determined by whether the reflection object holds the original item. When we say
   230  
   231  	    var x float64 = 3.4
   232  	    v := reflect.ValueOf(x)
   233  
   234  we pass a copy of `x` to `reflect.ValueOf`, so the interface value created as the argument to `reflect.ValueOf` is a copy of `x`, not `x` itself. Thus, if the statement
   235  
   236  	    v.SetFloat(7.1)
   237  
   238  were allowed to succeed, it would not update `x`, even though `v` looks like it was created from `x`. Instead, it would update the copy of `x` stored inside the reflection value and `x` itself would be unaffected. That would be confusing and useless, so it is illegal, and settability is the property used to avoid this issue.
   239  
   240  If this seems bizarre, it's not. It's actually a familiar situation in unusual garb. Think of passing `x` to a function:
   241  
   242  	f(x)
   243  
   244  We would not expect `f` to be able to modify `x` because we passed a copy of `x`'s value, not `x` itself. If we want `f` to modify `x` directly we must pass our function the address of `x` (that is, a pointer to `x`):
   245  
   246  	f(&x)
   247  
   248  This is straightforward and familiar, and reflection works the same way. If we want to modify `x` by reflection, we must give the reflection library a pointer to the value we want to modify.
   249  
   250  Let's do that. First we initialize `x` as usual and then create a reflection value that points to it, called `p`.
   251  
   252  	    var x float64 = 3.4
   253  	    p := reflect.ValueOf(&x) // Note: take the address of x.
   254  	    fmt.Println("type of p:", p.Type())
   255  	    fmt.Println("settability of p:", p.CanSet())
   256  
   257  The output so far is
   258  
   259  	type of p: *float64
   260  	settability of p: false
   261  
   262  The reflection object `p` isn't settable, but it's not `p` we want to set, it's (in effect) `*p`. To get to what `p` points to, we call the `Elem` method of `Value`, which indirects through the pointer, and save the result in a reflection `Value` called `v`:
   263  
   264  	    v := p.Elem()
   265  	    fmt.Println("settability of v:", v.CanSet())
   266  
   267  Now `v` is a settable reflection object, as the output demonstrates,
   268  
   269  	settability of v: true
   270  
   271  and since it represents `x`, we are finally able to use `v.SetFloat` to modify the value of `x`:
   272  
   273  	    v.SetFloat(7.1)
   274  	    fmt.Println(v.Interface())
   275  	    fmt.Println(x)
   276  
   277  The output, as expected, is
   278  
   279  	7.1
   280  	7.1
   281  
   282  Reflection can be hard to understand but it's doing exactly what the language does, albeit through reflection `Types` and `Values` that can disguise what's going on. Just keep in mind that reflection Values need the address of something in order to modify what they represent.
   283  
   284  * Structs
   285  
   286  In our previous example `v` wasn't a pointer itself, it was just derived from one. A common way for this situation to arise is when using reflection to modify the fields of a structure. As long as we have the address of the structure, we can modify its fields.
   287  
   288  Here's a simple example that analyzes a struct value, `t`. We create the reflection object with the address of the struct because we'll want to modify it later. Then we set `typeOfT` to its type and iterate over the fields using straightforward method calls (see [[http://golang.org/pkg/reflect/][package reflect]] for details). Note that we extract the names of the fields from the struct type, but the fields themselves are regular `reflect.Value` objects.
   289  
   290  	    type T struct {
   291  	        A int
   292  	        B string
   293  	    }
   294  	    t := T{23, "skidoo"}
   295  	    s := reflect.ValueOf(&t).Elem()
   296  	    typeOfT := s.Type()
   297  	    for i := 0; i < s.NumField(); i++ {
   298  	        f := s.Field(i)
   299  	        fmt.Printf("%d: %s %s = %v\n", i,
   300  	            typeOfT.Field(i).Name, f.Type(), f.Interface())
   301  	    }
   302  
   303  The output of this program is
   304  
   305  	0: A int = 23
   306  	1: B string = skidoo
   307  
   308  There's one more point about settability introduced in passing here: the field names of `T` are upper case (exported) because only exported fields of a struct are settable.
   309  
   310  Because `s` contains a settable reflection object, we can modify the fields of the structure.
   311  
   312  	    s.Field(0).SetInt(77)
   313  	    s.Field(1).SetString("Sunset Strip")
   314  	    fmt.Println("t is now", t)
   315  
   316  And here's the result:
   317  
   318  	t is now {77 Sunset Strip}
   319  
   320  If we modified the program so that `s` was created from `t`, not `&t`, the calls to `SetInt` and `SetString` would fail as the fields of `t` would not be settable.
   321  
   322  * Conclusion
   323  
   324  Here again are the laws of reflection:
   325  
   326  - Reflection goes from interface value to reflection object.
   327  
   328  - Reflection goes from reflection object to interface value.
   329  
   330  - To modify a reflection object, the value must be settable.
   331  
   332  Once you understand these laws reflection in Go becomes much easier to use, although it remains subtle. It's a powerful tool that should be used with care and avoided unless strictly necessary.
   333  
   334  There's plenty more to reflection that we haven't covered — sending and receiving on channels, allocating memory, using slices and maps, calling methods and functions — but this post is long enough. We'll cover some of those topics in a later article.