structure: add ToSlice() , closes #3

This commit is contained in:
Fatih Arslan 2014-07-27 16:53:29 +03:00
parent e10d13000f
commit e8a7d20d51
4 changed files with 103 additions and 6 deletions

View File

@ -32,10 +32,21 @@ if err != nil {
panic(err)
}
fmt.Printf("%#v", m)
// prints: map[string]interface {}{"Name":"Arslan", "ID":123456, "Enabled":true}
fmt.Printf("%#v", m)
```
```go
// convert it to a []interface{}. Slice values are sorted according to the
// field names.
m, err := structure.ToSlice(s)
if err != nil {
panic(err)
}
// prints: []interface {}{true, 123456, "Arslan"}
fmt.Printf("%#v", m)
```go
// check if it's a struct or a pointer to struct
if structure.IsStruct(s) {

View File

@ -4,6 +4,7 @@ package structure
import (
"errors"
"reflect"
"sort"
)
// ErrNotStruct is returned when the passed value is not a struct
@ -13,11 +14,11 @@ var ErrNotStruct = errors.New("not struct")
// string is the struct fieldname but this can be changed by defining a
// "structure" tag key if needed. Note that only exported fields of a struct
// can be accessed, non exported fields will be neglected.
func ToMap(in interface{}) (map[string]interface{}, error) {
func ToMap(s interface{}) (map[string]interface{}, error) {
out := make(map[string]interface{})
t := reflect.TypeOf(in)
v := reflect.ValueOf(in)
t := reflect.TypeOf(s)
v := reflect.ValueOf(s)
// if pointer get the underlying element≤
if t.Kind() == reflect.Ptr {
@ -50,10 +51,38 @@ func ToMap(in interface{}) (map[string]interface{}, error) {
return out, nil
}
// ToSlice converts a struct's field values to a []interface{}. Values are
// inserted and sorted according to the field names. Note that only exported
// fields of a struct can be accessed, non exported fields will be neglected.
func ToSlice(s interface{}) ([]interface{}, error) {
m, err := ToMap(s)
if err != nil {
return nil, err
}
keys := make([]string, len(m))
count := 0
for k := range m {
keys[count] = k
count++
}
sort.Strings(keys)
t := make([]interface{}, len(m))
for i, key := range keys {
t[i] = m[key]
}
return t, nil
}
// IsStruct returns true if the given variable is a struct or a pointer to
// struct.
func IsStruct(strct interface{}) bool {
t := reflect.TypeOf(strct)
func IsStruct(s interface{}) bool {
t := reflect.TypeOf(s)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}

View File

@ -58,3 +58,27 @@ func ExampleToMap_tags() {
// false
}
func ExampleToSlice() {
type Server struct {
Name string
ID int32
Enabled bool
}
s := &Server{
Name: "Fatih",
ID: 135790,
Enabled: false,
}
m, err := ToSlice(s)
if err != nil {
panic(err)
}
// note that the output is sorted according to the field names
fmt.Printf("%#v\n", m)
// Output:
// []interface {}{false, 135790, "Fatih"}
}

View File

@ -105,3 +105,36 @@ func TestStruct(t *testing.T) {
}
}
func TestToSlice(t *testing.T) {
var T = struct {
A string
B int
C bool
}{
A: "a-value",
B: 2,
C: true,
}
s, err := ToSlice(T)
if err != nil {
t.Error(err)
}
inSlice := func(val interface{}) bool {
for _, v := range s {
if reflect.DeepEqual(v, val) {
return true
}
}
return false
}
for _, val := range []interface{}{"a-value", 2, true} {
if !inSlice(val) {
t.Errorf("ToSlice should have the value %v", val)
}
}
}