forked from gophercon/2016-talks
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added README.md for the power and elegance of reflection
- Loading branch information
1 parent
eed97a6
commit da08c34
Showing
11 changed files
with
605 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
49
EmilyGu-PowerAndEleganceOfReflection/code/basics/map/map.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
EmilyGu-PowerAndEleganceOfReflection/code/basics/pointer/pointer.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
49
EmilyGu-PowerAndEleganceOfReflection/code/basics/slice/slice.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
35
EmilyGu-PowerAndEleganceOfReflection/code/basics/struct/struct.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()) | ||
} |
93 changes: 93 additions & 0 deletions
93
EmilyGu-PowerAndEleganceOfReflection/code/inspect/integer/integer.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
Oops, something went wrong.