Skip to content

Instantly share code, notes, and snippets.

@oyakata
Created November 30, 2017 09:42
Show Gist options
  • Save oyakata/e454a354a942a282e9794e26e5700c6f to your computer and use it in GitHub Desktop.
Save oyakata/e454a354a942a282e9794e26e5700c6f to your computer and use it in GitHub Desktop.
Goでstructのフィールドを[][]interface{}に変換
package main
import (
"fmt"
"reflect"
"time"
"unsafe"
)
var timeType = reflect.TypeOf(time.Time{})
func Inspect(items interface{}) ([]reflect.StructField, [][]interface{}) {
v := reflect.ValueOf(items)
if v.Len() == 0 {
return nil, nil
}
vs := make([]reflect.Value, v.Len())
for i := 0; i < v.Len(); i++ {
vs[i] = v.Index(i)
}
t := vs[0].Type()
fields := make([]reflect.StructField, t.NumField())
for i := 0; i < t.NumField(); i++ {
fields[i] = t.Field(i)
}
xs := make([][]interface{}, v.Len())
for i, x := range vs {
values := make([]interface{}, len(fields))
for j, f := range fields {
v := x.FieldByName(f.Name)
var r interface{}
switch v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
r = v.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
r = v.Uint()
case reflect.Float32, reflect.Float64:
r = v.Float()
case reflect.String:
r = v.String()
case reflect.Bool:
r = v.Bool()
case reflect.Slice:
r = v.Bytes()
default:
if v.Type().ConvertibleTo(timeType) {
tt := (*time.Time)(unsafe.Pointer(v.Addr().Pointer()))
r = *tt
}
}
values[j] = r
}
xs[i] = values
}
return fields, xs
}
func main() {
xs := []struct {
id int
name string
age uint8
superuser bool
b []byte
bb [1]byte
birthday time.Time
}{
{1, "imagawa", 13, false, []byte("imgw"), [1]byte{}, time.Now()},
{2, "yoshimot", 20, true, nil, [1]byte{}, time.Time{}},
{3, "moyomot", 35, false, nil, [1]byte{1}, time.Now()},
}
fields, items := Inspect(xs)
fmt.Println(fields)
for _, x := range items {
fmt.Println(x)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment