Skip to content

Instantly share code, notes, and snippets.

@shal
Last active October 2, 2019 20:21
Show Gist options
  • Save shal/eda6cca5f0da475045968ae414df2aca to your computer and use it in GitHub Desktop.
Save shal/eda6cca5f0da475045968ae414df2aca to your computer and use it in GitHub Desktop.
Golang reflect play
package main
import (
"errors"
"fmt"
"os"
"reflect"
"strconv"
"strings"
)
type Point struct {
X uint64
Y string
Z int32
}
func ToStuct(row string, value interface{}) error {
return toStruct(row, reflect.ValueOf(value).Elem())
}
func ToCSV(value interface{}) (string, error) {
return toCSV(reflect.ValueOf(value).Elem())
}
func toStruct(row string, v reflect.Value) error {
lexems := strings.Split(row, ",")
if len(lexems) != v.NumField() {
return errors.New("invalid amount of fields")
}
for i := 0; i < v.NumField(); i++ {
fx := v.Field(i)
switch fx.Kind() {
case reflect.String:
s, _ := strconv.Unquote(lexems[i])
fx.SetString(s)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
s, _ := strconv.ParseUint(lexems[i], 10, 64)
fx.SetUint(s)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
s, _ := strconv.ParseInt(lexems[i], 10, 64)
fx.SetInt(s)
}
}
return nil
}
func toCSV(v reflect.Value) (string, error) {
str := strings.Builder{}
for i := 0; i < v.NumField(); i++ {
fx := v.Field(i)
switch fx.Kind() {
case reflect.String:
s, _ := strconv.Unquote(strconv.Quote(fx.String()))
str.WriteString(s)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
str.WriteString(strconv.FormatUint(fx.Uint(), 10))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
str.WriteString(strconv.FormatInt(fx.Int(), 10))
}
if i != v.NumField()-1 {
str.WriteString(", ")
}
}
return str.String(), nil
}
func main() {
p := new(Point)
err := ToStuct("1,\"hello\",112", p)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(*p)
res, err := ToCSV(p)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(res)
}
package main
import (
"fmt"
"net/http"
"os"
"reflect"
"strconv"
)
func Unpack(r *http.Request, v interface{}) error {
if err := r.ParseForm(); err != nil {
return err
}
fields := make(map[string]reflect.Value)
obj := reflect.ValueOf(v).Elem()
for i := 0; i < obj.NumField(); i++ {
fieldType := obj.Type().Field(i)
tag := fieldType.Tag.Get("http")
fields[tag] = obj.Field(i)
}
for name, values := range r.Form {
f := fields[name]
if !f.IsValid() {
continue
}
for _, value := range values {
switch f.Kind() {
case reflect.Bool:
res, err := strconv.ParseBool(value)
if err != nil {
return err
}
f.SetBool(res)
}
// TODO: other...
}
}
return nil
}
func ExampleHandler(w http.ResponseWriter, r *http.Request) {
var data struct {
X bool `http:"x"`
}
err := Unpack(r, &data)
if err != nil {
http.Error(w, err.Error(), 400)
}
fmt.Fprintf(w, "Search %+v\n", data)
}
func main() {
http.HandleFunc("/", ExampleHandler)
err := http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Fprint(os.Stderr, err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment