diff options
Diffstat (limited to 'doc/articles/laws_of_reflection.html')
-rw-r--r-- | doc/articles/laws_of_reflection.html | 152 |
1 files changed, 27 insertions, 125 deletions
diff --git a/doc/articles/laws_of_reflection.html b/doc/articles/laws_of_reflection.html index 4df70e0d2..a6175f73c 100644 --- a/doc/articles/laws_of_reflection.html +++ b/doc/articles/laws_of_reflection.html @@ -1,11 +1,7 @@ <!--{ - "Title": "The Laws of Reflection" + "Title": "The Laws of Reflection", + "Template": true }--> -<!-- - DO NOT EDIT: created by - tmpltohtml articles/laws_of_reflection.tmpl ---> - <p> Reflection in computing is the @@ -36,11 +32,7 @@ exactly one type known and fixed at compile time: <code>int</code>, and so on. If we declare </p> -<pre><!--{{code "progs/interface.go" `/type MyInt/` `/STOP/`}} --->type MyInt int - -var i int -var j MyInt</pre> +{{code "/doc/progs/interface.go" `/type MyInt/` `/STOP/`}} <p> then <code>i</code> has type <code>int</code> and <code>j</code> @@ -60,16 +52,7 @@ interface's methods. A well-known pair of examples is "http://golang.org/pkg/io/">io package</a>: </p> -<pre><!--{{code "progs/interface.go" `/// Reader/` `/STOP/`}} --->// Reader is the interface that wraps the basic Read method. -type Reader interface { - Read(p []byte) (n int, err error) -} - -// Writer is the interface that wraps the basic Write method. -type Writer interface { - Write(p []byte) (n int, err error) -}</pre> +{{code "/doc/progs/interface.go" `/// Reader/` `/STOP/`}} <p> Any type that implements a <code>Read</code> (or @@ -80,12 +63,7 @@ purposes of this discussion, that means that a variable of type <code>Read</code> method: </p> -<pre><!--{{code "progs/interface.go" `/func readers/` `/STOP/`}} ---> var r io.Reader - r = os.Stdin - r = bufio.NewReader(r) - r = new(bytes.Buffer) - // and so on</pre> +{{code "/doc/progs/interface.go" `/func readers/` `/STOP/`}} <p> It's important to be clear that whatever concrete value @@ -138,13 +116,7 @@ that implements the interface and the type describes the full type of that item. For instance, after </p> -<pre><!--{{code "progs/interface.go" `/func typeAssertions/` `/STOP/`}} ---> var r io.Reader - tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0) - if err != nil { - return nil, err - } - r = tty</pre> +{{code "/doc/progs/interface.go" `/func typeAssertions/` `/STOP/`}} <p> <code>r</code> contains, schematically, the (value, type) pair, @@ -156,9 +128,7 @@ the type information about that value. That's why we can do things like this: </p> -<pre><!--{{code "progs/interface.go" `/var w io.Writer/` `/STOP/`}} ---> var w io.Writer - w = r.(io.Writer)</pre> +{{code "/doc/progs/interface.go" `/var w io.Writer/` `/STOP/`}} <p> The expression in this assignment is a type assertion; what it @@ -176,9 +146,7 @@ methods. Continuing, we can do this: </p> -<pre><!--{{code "progs/interface.go" `/var empty interface{}/` `/STOP/`}} ---> var empty interface{} - empty = w</pre> +{{code "/doc/progs/interface.go" `/var empty interface{}/` `/STOP/`}} <p> and our empty interface value <code>e</code> will again contain @@ -216,7 +184,7 @@ 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 <a href="http://golang.org/pkg/reflect">package reflect</a>: -<a href="http://golang.org/pkg/reflect/#Type">Type</a>and +<a href="http://golang.org/pkg/reflect/#Type">Type</a> and <a href="http://golang.org/pkg/reflect/#Value">Value</a>. Those two types give access to the contents of an interface variable, and two simple functions, called <code>reflect.TypeOf</code> and @@ -232,18 +200,7 @@ now.) Let's start with <code>TypeOf</code>: </p> -<pre><!--{{code "progs/interface2.go" `/package main/` `/STOP main/`}} --->package main - -import ( - "fmt" - "reflect" -) - -func main() { - var x float64 = 3.4 - fmt.Println("type:", reflect.TypeOf(x)) -}</pre> +{{code "/doc/progs/interface2.go" `/package main/` `/STOP main/`}} <p> This program prints @@ -281,9 +238,7 @@ value (from here on we'll elide the boilerplate and focus just on the executable code): </p> -<pre><!--{{code "progs/interface2.go" `/var x/` `/STOP/`}} ---> var x float64 = 3.4 - fmt.Println("type:", reflect.TypeOf(x))</pre> +{{code "/doc/progs/interface2.go" `/START f9/` `/STOP/`}} <p> prints @@ -307,12 +262,7 @@ on. Also methods on <code>Value</code> with names like <code>int64</code> and <code>float64</code>) stored inside: </p> -<pre><!--{{code "progs/interface2.go" `/START f1/` `/STOP/`}} ---> var x float64 = 3.4 - v := reflect.ValueOf(x) - fmt.Println("type:", v.Type()) - fmt.Println("kind is float64:", v.Kind() == reflect.Float64) - fmt.Println("value:", v.Float())</pre> +{{code "/doc/progs/interface2.go" `/START f1/` `/STOP/`}} <p> prints @@ -342,12 +292,7 @@ instance. That is, the <code>Int</code> method of necessary to convert to the actual type involved: </p> -<pre><!--{{code "progs/interface2.go" `/START f2/` `/STOP/`}} ---> var x uint8 = 'x' - v := reflect.ValueOf(x) - fmt.Println("type:", v.Type()) // uint8. - fmt.Println("kind is uint8: ", v.Kind() == reflect.Uint8) // true. - x = uint8(v.Uint()) // v.Uint returns a uint64.</pre> +{{code "/doc/progs/interface2.go" `/START f2/` `/STOP/`}} <p> The second property is that the <code>Kind</code> of a reflection @@ -356,10 +301,7 @@ reflection object contains a value of a user-defined integer type, as in </p> -<pre><!--{{code "progs/interface2.go" `/START f3/` `/START/`}} ---> type MyInt int - var x MyInt = 7 - v := reflect.ValueOf(x)</pre> +{{code "/doc/progs/interface2.go" `/START f3/` `/STOP/`}} <p> the <code>Kind</code> of <code>v</code> is still @@ -395,9 +337,7 @@ func (v Value) Interface() interface{} As a consequence we can say </p> -<pre><!--{{code "progs/interface2.go" `/START f3b/` `/START/`}} ---> y := v.Interface().(float64) // y will have type float64. - fmt.Println(y)</pre> +{{code "/doc/progs/interface2.go" `/START f3b/` `/STOP/`}} <p> to print the <code>float64</code> value represented by the @@ -415,8 +355,7 @@ the <code>Interface</code> method to the formatted print routine: </p> -<pre><!--{{code "progs/interface2.go" `/START f3c/` `/START/`}} ---> fmt.Println(v.Interface())</pre> +{{code "/doc/progs/interface2.go" `/START f3c/` `/STOP/`}} <p> (Why not <code>fmt.Println(v)</code>? Because <code>v</code> is a @@ -425,8 +364,7 @@ Since our value is a <code>float64</code>, we can even use a floating-point format if we want: </p> -<pre><!--{{code "progs/interface2.go" `/START f3d/` `/STOP/`}} ---> fmt.Printf("value is %7.1e\n", v.Interface())</pre> +{{code "/doc/progs/interface2.go" `/START f3d/` `/STOP/`}} <p> and get in this case @@ -467,10 +405,7 @@ enough to understand if we start from first principles. Here is some code that does not work, but is worth studying. </p> -<pre><!--{{code "progs/interface2.go" `/START f4/` `/STOP/`}} ---> var x float64 = 3.4 - v := reflect.ValueOf(x) - v.SetFloat(7.1) // Error: will panic.</pre> +{{code "/doc/progs/interface2.go" `/START f4/` `/STOP/`}} <p> If you run this code, it will panic with the cryptic message @@ -492,10 +427,7 @@ The <code>CanSet</code> method of <code>Value</code> reports the settability of a <code>Value</code>; in our case, </p> -<pre><!--{{code "progs/interface2.go" `/START f5/` `/STOP/`}} ---> var x float64 = 3.4 - v := reflect.ValueOf(x) - fmt.Println("settability of v:", v.CanSet())</pre> +{{code "/doc/progs/interface2.go" `/START f5/` `/STOP/`}} <p> prints @@ -518,9 +450,7 @@ determined by whether the reflection object holds the original item. When we say </p> -<pre><!--{{code "progs/interface2.go" `/START f6/` `/START/`}} ---> var x float64 = 3.4 - v := reflect.ValueOf(x)</pre> +{{code "/doc/progs/interface2.go" `/START f6/` `/STOP/`}} <p> we pass a <em>copy</em> of <code>x</code> to @@ -530,8 +460,7 @@ argument to <code>reflect.ValueOf</code> is a <em>copy</em> of statement </p> -<pre><!--{{code "progs/interface2.go" `/START f6b/` `/STOP/`}} ---> v.SetFloat(7.1)</pre> +{{code "/doc/progs/interface2.go" `/START f6b/` `/STOP/`}} <p> were allowed to succeed, it would not update <code>x</code>, even @@ -577,11 +506,7 @@ and then create a reflection value that points to it, called <code>p</code>. </p> -<pre><!--{{code "progs/interface2.go" `/START f7/` `/START/`}} ---> var x float64 = 3.4 - p := reflect.ValueOf(&x) // Note: take the address of x. - fmt.Println("type of p:", p.Type()) - fmt.Println("settability of p:", p.CanSet())</pre> +{{code "/doc/progs/interface2.go" `/START f7/` `/STOP/`}} <p> The output so far is @@ -601,9 +526,7 @@ and save the result in a reflection <code>Value</code> called <code>v</code>: </p> -<pre><!--{{code "progs/interface2.go" `/START f7b/` `/START/`}} ---> v := p.Elem() - fmt.Println("settability of v:", v.CanSet())</pre> +{{code "/doc/progs/interface2.go" `/START f7b/` `/STOP/`}} <p> Now <code>v</code> is a settable reflection object, as the output @@ -620,10 +543,7 @@ and since it represents <code>x</code>, we are finally able to use <code>x</code>: </p> -<pre><!--{{code "progs/interface2.go" `/START f7c/` `/STOP/`}} ---> v.SetFloat(7.1) - fmt.Println(v.Interface()) - fmt.Println(x)</pre> +{{code "/doc/progs/interface2.go" `/START f7c/` `/STOP/`}} <p> The output, as expected, is @@ -664,22 +584,7 @@ but the fields themselves are regular <code>reflect.Value</code> objects. </p> -<pre><!--{{code "progs/interface2.go" `/START f8/` `/STOP/`}} ---> type T struct { - A int - B string - } - t := T{23, "skidoo"} - s := reflect.ValueOf(&t).Elem() - typeOfT := s.Type() - for i := 0; i < s.NumField(); i++ { - f := s.Field(i) - fmt.Printf("%d: %s %s = %v\n", i, - typeOfT.Field(i).Name, f.Type(), f.Interface()) - } - s.Field(0).SetInt(77) - s.Field(1).SetString("Sunset Strip") - fmt.Println("t is now", t)</pre> +{{code "/doc/progs/interface2.go" `/START f8/` `/STOP/`}} <p> The output of this program is @@ -702,10 +607,7 @@ Because <code>s</code> contains a settable reflection object, we can modify the fields of the structure. </p> -<pre><!--{{code "progs/interface2.go" `/START f8b/` `/STOP/`}} ---> s.Field(0).SetInt(77) - s.Field(1).SetString("Sunset Strip") - fmt.Println("t is now", t)</pre> +{{code "/doc/progs/interface2.go" `/START f8b/` `/STOP/`}} <p> And here's the result: @@ -749,4 +651,4 @@ 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. -</p>
\ No newline at end of file +</p> |