structure: remove returning error, it should panic just like reflect
package
This commit is contained in:
parent
68345fdc8f
commit
afdeeccc8b
10
README.md
10
README.md
@ -31,10 +31,7 @@ s := &Server{
|
|||||||
Convert to a `map[string]interface{}`
|
Convert to a `map[string]interface{}`
|
||||||
|
|
||||||
```go
|
```go
|
||||||
m, err := structure.ToMap(s)
|
m := structure.ToMap(s)
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// prints: map[string]interface {}{"Name":"Arslan", "ID":123456, "Enabled":true}
|
// prints: map[string]interface {}{"Name":"Arslan", "ID":123456, "Enabled":true}
|
||||||
fmt.Printf("%#v", m)
|
fmt.Printf("%#v", m)
|
||||||
@ -46,10 +43,7 @@ Convert to a `[]interface{}`. Slice values are **sorted** by default according
|
|||||||
to the field names.
|
to the field names.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
m, err := structure.ToSlice(s)
|
m := structure.ToSlice(s)
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// prints: []interface {}{true, 123456, "Arslan"}
|
// prints: []interface {}{true, 123456, "Arslan"}
|
||||||
fmt.Printf("%#v", m)
|
fmt.Printf("%#v", m)
|
||||||
|
|||||||
51
structure.go
51
structure.go
@ -2,19 +2,16 @@
|
|||||||
package structure
|
package structure
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrNotStruct is returned when the passed value is not a struct
|
// ToMap converts the given s struct to a map[string]interface{}. The default
|
||||||
var ErrNotStruct = errors.New("not struct")
|
// map key names are the struct fieldnames but this can be changed by defining
|
||||||
|
// a "structure" tag key if needed. Note that only exported fields of a struct
|
||||||
// ToMap converts a struct to a map[string]interface{}. The default map key
|
// can be accessed, non exported fields will be neglected. It panics if s's
|
||||||
// string is the struct fieldname but this can be changed by defining a
|
// kind is not struct.
|
||||||
// "structure" tag key if needed. Note that only exported fields of a struct
|
func ToMap(s interface{}) map[string]interface{} {
|
||||||
// can be accessed, non exported fields will be neglected.
|
|
||||||
func ToMap(s interface{}) (map[string]interface{}, error) {
|
|
||||||
out := make(map[string]interface{})
|
out := make(map[string]interface{})
|
||||||
|
|
||||||
t := reflect.TypeOf(s)
|
t := reflect.TypeOf(s)
|
||||||
@ -27,7 +24,7 @@ func ToMap(s interface{}) (map[string]interface{}, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if t.Kind() != reflect.Struct {
|
if t.Kind() != reflect.Struct {
|
||||||
return nil, ErrNotStruct
|
panic("not struct")
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < t.NumField(); i++ {
|
for i := 0; i < t.NumField(); i++ {
|
||||||
@ -48,17 +45,15 @@ func ToMap(s interface{}) (map[string]interface{}, error) {
|
|||||||
out[name] = v.Field(i).Interface()
|
out[name] = v.Field(i).Interface()
|
||||||
}
|
}
|
||||||
|
|
||||||
return out, nil
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToSlice converts a struct's field values to a []interface{}. Values are
|
// ToSlice converts the given s struct's field values to a []interface{}.
|
||||||
// inserted and sorted according to the field names. Note that only exported
|
// Values are inserted and sorted according to the field names. Note that only
|
||||||
// fields of a struct can be accessed, non exported fields will be neglected.
|
// exported fields of a struct can be accessed, non exported fields will be
|
||||||
func ToSlice(s interface{}) ([]interface{}, error) {
|
// neglected. It panics if s's kind is not struct.
|
||||||
m, err := ToMap(s)
|
func ToSlice(s interface{}) []interface{} {
|
||||||
if err != nil {
|
m := ToMap(s)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
keys := make([]string, len(m))
|
keys := make([]string, len(m))
|
||||||
count := 0
|
count := 0
|
||||||
@ -75,10 +70,26 @@ func ToSlice(s interface{}) ([]interface{}, error) {
|
|||||||
t[i] = m[key]
|
t[i] = m[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
return t, nil
|
return t
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fields returns a sorted slice of field names.
|
||||||
|
func Fields(s interface{}) []string {
|
||||||
|
m := ToMap(s)
|
||||||
|
|
||||||
|
keys := make([]string, len(m))
|
||||||
|
count := 0
|
||||||
|
for k := range m {
|
||||||
|
keys[count] = k
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
// IsStruct returns true if the given variable is a struct or a pointer to
|
// IsStruct returns true if the given variable is a struct or a pointer to
|
||||||
// struct.
|
// struct.
|
||||||
func IsStruct(s interface{}) bool {
|
func IsStruct(s interface{}) bool {
|
||||||
|
|||||||
@ -15,10 +15,7 @@ func ExampleToMap() {
|
|||||||
Enabled: true,
|
Enabled: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err := ToMap(s)
|
m := ToMap(s)
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("%#v\n", m["Name"])
|
fmt.Printf("%#v\n", m["Name"])
|
||||||
fmt.Printf("%#v\n", m["ID"])
|
fmt.Printf("%#v\n", m["ID"])
|
||||||
@ -43,10 +40,7 @@ func ExampleToMap_tags() {
|
|||||||
ID: 789012,
|
ID: 789012,
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err := ToMap(s)
|
m := ToMap(s)
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// access them by the custom tags defined above
|
// access them by the custom tags defined above
|
||||||
fmt.Printf("%#v\n", m["server_name"])
|
fmt.Printf("%#v\n", m["server_name"])
|
||||||
@ -72,10 +66,7 @@ func ExampleToSlice() {
|
|||||||
Enabled: false,
|
Enabled: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err := ToSlice(s)
|
m := ToSlice(s)
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// note that the output is sorted according to the field names
|
// note that the output is sorted according to the field names
|
||||||
fmt.Printf("%#v\n", m)
|
fmt.Printf("%#v\n", m)
|
||||||
|
|||||||
@ -8,11 +8,15 @@ import (
|
|||||||
func TestToMapNonStruct(t *testing.T) {
|
func TestToMapNonStruct(t *testing.T) {
|
||||||
foo := []string{"foo"}
|
foo := []string{"foo"}
|
||||||
|
|
||||||
_, err := ToMap(foo)
|
defer func() {
|
||||||
if err == nil {
|
err := recover()
|
||||||
t.Error("ToMap shouldn't accept non struct types")
|
if err == nil {
|
||||||
}
|
t.Error("Passing a non struct into ToMap should panic")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// this should panic. We are going to recover and and test it
|
||||||
|
_ = ToMap(foo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestToMap(t *testing.T) {
|
func TestToMap(t *testing.T) {
|
||||||
@ -26,10 +30,7 @@ func TestToMap(t *testing.T) {
|
|||||||
C: true,
|
C: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
a, err := ToMap(T)
|
a := ToMap(T)
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if typ := reflect.TypeOf(a).Kind(); typ != reflect.Map {
|
if typ := reflect.TypeOf(a).Kind(); typ != reflect.Map {
|
||||||
t.Errorf("ToMap should return a map type, got: %v", typ)
|
t.Errorf("ToMap should return a map type, got: %v", typ)
|
||||||
@ -69,19 +70,14 @@ func TestToMap_Tag(t *testing.T) {
|
|||||||
C: true,
|
C: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
a, err := ToMap(T)
|
a := ToMap(T)
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
inMap := func(key interface{}) bool {
|
inMap := func(key interface{}) bool {
|
||||||
for k := range a {
|
for k := range a {
|
||||||
if reflect.DeepEqual(k, key) {
|
if reflect.DeepEqual(k, key) {
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,10 +113,7 @@ func TestToSlice(t *testing.T) {
|
|||||||
C: true,
|
C: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := ToSlice(T)
|
s := ToSlice(T)
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
inSlice := func(val interface{}) bool {
|
inSlice := func(val interface{}) bool {
|
||||||
for _, v := range s {
|
for _, v := range s {
|
||||||
@ -128,7 +121,6 @@ func TestToSlice(t *testing.T) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user