Skip to content

Commit

Permalink
added README.md for the power and elegance of reflection
Browse files Browse the repository at this point in the history
  • Loading branch information
candysmurf committed Jul 16, 2016
1 parent eed97a6 commit da08c34
Show file tree
Hide file tree
Showing 11 changed files with 605 additions and 0 deletions.
49 changes: 49 additions & 0 deletions EmilyGu-PowerAndEleganceOfReflection/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
## Reflection - Standard Library

Developers are often told reflection is bad and should be avoided. However, when reflection can help reduce the amount of code needed to solve a problem, it should be considered. Reducing complexity while preserving maintainability must always be a priority. Reflection can be a tool that helps makes this possible. In this talk I am going to show you the power and elegance of the reflection package.

https://candysmurf.github.io/GoReflectionTalk

## Links

http://blog.golang.org/laws-of-reflection

## Code Review

### Basics

Example shows how to reflect over a struct type value.
[Struct Types](code/basics/struct/struct.go) ([Go Playground](https://play.golang.org/p/_b73a7uUOx))

Example shows how to reflect over a slice of struct type values.
[Slices](code/basics/slice/slice.go) ([Go Playground](https://play.golang.org/p/S4IKEOvbHG))

Example shows how to reflect over a map of struct type values.
[Maps](code/basics/map/map.go) ([Go Playground](https://play.golang.org/p/3j6gT94Ji3))

Example shows how to reflect over a struct type pointer.
[Pointers](code/basics/pointer/pointer.go) ([Go Playground](https://play.golang.org/p/2zMmWmSNgY))

### Interfaces

Example shows how to reflect over a struct type value that is stored inside an interface value.
[Struct Types](code/interface/struct/struct.go) ([Go Playground](https://play.golang.org/p/vdOHbCHO-c))

Example shows how to reflect over a slice of struct type values that are stored inside an interface value.
[Slices](code/interface/slice/slice.go) ([Go Playground](https://play.golang.org/p/YXeogyWr-H))

Example shows how to reflect over a map of struct type values that are stored inside an interface value.
[Maps](code/interface/map/map.go) ([Go Playground](https://play.golang.org/p/mZIYNXBdF-))

Example shows how to reflect over a struct type pointer that is stored inside an interface value.
[Pointers](code/interface/pointer/pointer.go) ([Go Playground](https://play.golang.org/p/7XUMzJ3hql))

### Inspection / Decoding

Example shows how to inspect a structs fields and display the field name, type and value.
[Struct Types](code/inspect/struct/struct.go) ([Go Playground](https://play.golang.org/p/71xtyS_sts))

Example shows how to use reflection to decode an integer.
[Integers](code/interface/integer/integer.go) ([Go Playground](https://play.golang.org/p/q-EIfJZUI-))
___
All material is licensed under the [Apache License Version 2.0, June 2016](http://www.apache.org/licenses/LICENSE-2.0).
49 changes: 49 additions & 0 deletions EmilyGu-PowerAndEleganceOfReflection/code/basics/map/map.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// All material is licensed under the Apache License Version 2.0, June 2016
// http://www.apache.org/licenses/LICENSE-2.0

// Example shows how to reflect over a map of struct type values.
package main

import (
"fmt"
"reflect"
)

// user represents a basic user in the system.
type user struct {
name string
age int
building float32
secure bool
roles []string
}

func main() {

// Create a map of struct type user values.
um := map[string]user{
"Cindy": {
name: "Cindy",
age: 27,
building: 321.45,
secure: true,
roles: []string{"admin", "developer"},
},
"Bill": {
name: "Bill",
age: 40,
building: 456.21,
secure: false,
roles: []string{"developer"},
},
}

// Display the information about the map of users values.
v := reflect.ValueOf(um)
fmt.Printf("Kind: %v\tType: %v\n", v.Kind(), v.Type())

// Iterate over the map via reflection.
for i, key := range v.MapKeys() {
fmt.Println(i, ":", v.MapIndex(key))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// All material is licensed under the Apache License Version 2.0, June 2016
// http://www.apache.org/licenses/LICENSE-2.0

// Example shows how to reflect over a struct type pointer.
package main

import (
"fmt"
"reflect"
)

// user represents a basic user in the system.
type user struct {
name string
age int
building float32
secure bool
roles []string
}

func main() {

// Create a struct type user value.
u := user{
name: "Cindy",
age: 27,
building: 321.45,
secure: true,
roles: []string{"admin", "developer"},
}

// Display the information about the pointer value.
v := reflect.ValueOf(&u)
fmt.Printf("Kind: %v\tType: %v\n", v.Kind(), v.Type())

// Inspect the value that the pointer points to.
v = v.Elem()
fmt.Printf("Kind: %v\tType: %v\t\tNumFields: %v\n", v.Kind(), v.Type(), v.NumField())
}
49 changes: 49 additions & 0 deletions EmilyGu-PowerAndEleganceOfReflection/code/basics/slice/slice.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// All material is licensed under the Apache License Version 2.0, June 2016
// http://www.apache.org/licenses/LICENSE-2.0

// Example shows how to reflect over a slice of struct type values.
package main

import (
"fmt"
"reflect"
)

// user represents a basic user in the system.
type user struct {
name string
age int
building float32
secure bool
roles []string
}

func main() {

// Create a slice of struct type user values.
us := []user{
{
name: "Cindy",
age: 27,
building: 321.45,
secure: true,
roles: []string{"admin", "developer"},
},
{
name: "Bill",
age: 40,
building: 456.21,
secure: false,
roles: []string{"developer"},
},
}

// Display the information about the slice of users values.
v := reflect.ValueOf(us)
fmt.Printf("Kind: %v\tType: %v\n", v.Kind(), v.Type())

// Iterate over the slice via reflection.
for i := 0; i < v.Len(); i++ {
fmt.Println(v.Index(i))
}
}
35 changes: 35 additions & 0 deletions EmilyGu-PowerAndEleganceOfReflection/code/basics/struct/struct.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// All material is licensed under the Apache License Version 2.0, June 2016
// http://www.apache.org/licenses/LICENSE-2.0

// Example shows how to reflect over a struct type value.
package main

import (
"fmt"
"reflect"
)

// user represents a basic user in the system.
type user struct {
name string
age int
building float32
secure bool
roles []string
}

func main() {

// Create a struct type user value.
u := user{
name: "Cindy",
age: 27,
building: 321.45,
secure: true,
roles: []string{"admin", "developer"},
}

// Display the information about the user value.
v := reflect.ValueOf(u)
fmt.Printf("Kind: %v\tType: %v\t\tNumFields: %v\n", v.Kind(), v.Type(), v.NumField())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// All material is licensed under the Apache License Version 2.0, January 2016
// http://www.apache.org/licenses/LICENSE-2.0

// Example shows how reflection provides integrity.
package main

import (
"fmt"
"reflect"
"strconv"
)

func main() {

// Decode the string into the integer variable.
var number int
decodeInt("10", &number)
fmt.Println("number:", number)

// Decode the integer into the integer variable.
var age int
decodeInt(45, &age)
fmt.Println("age:", age)
}

// decodeInt accepts a value of any type and will decode
// that value to an integer.
func decodeInt(v interface{}, number *int) error {

// Inspect the concrete type value that is passed in.
rv := reflect.ValueOf(v)

// Retrieve the value that the integer pointer points to.
val := reflect.ValueOf(number).Elem()

// Based on the kind of data to decode, perform the specific logic.
switch getKind(rv) {

case reflect.Int:
val.SetInt(rv.Int())

case reflect.Uint:
val.SetInt(int64(rv.Uint()))

case reflect.Float32:
val.SetInt(int64(rv.Float()))

case reflect.Bool:
if rv.Bool() {
val.SetInt(1)
return nil
}

val.SetInt(0)

case reflect.String:
i, err := strconv.ParseInt(rv.String(), 0, val.Type().Bits())
if err != nil {
return fmt.Errorf("cannot parse as int: %s", err)
}

val.SetInt(i)

default:
return fmt.Errorf("expected type '%s', got unconvertible type '%s'", val.Type(), rv.Type())
}

return nil
}

// getKind provides support for identifying predeclared numeric
// types with implementation-specific sizes.
func getKind(val reflect.Value) reflect.Kind {

// Capture the value's Kind.
kind := val.Kind()

// Check each condition until a case is true.
switch {

case kind >= reflect.Int && kind <= reflect.Int64:
return reflect.Int

case kind >= reflect.Uint && kind <= reflect.Uint64:
return reflect.Uint

case kind >= reflect.Float32 && kind <= reflect.Float64:
return reflect.Float32

default:
return kind
}
}
Loading

0 comments on commit da08c34

Please sign in to comment.