From eeb4d315720da6dbf1986c834125e35fabfd76fc Mon Sep 17 00:00:00 2001 From: ehlxr Date: Mon, 29 Jan 2018 12:47:06 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AB=99=E7=82=B9=E6=9B=B4=E6=96=B0=EF=BC=9A20?= =?UTF-8?q?18-01-29=2012:47:06?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/reflect/main.go | 127 +++++++++++++++++++++++++++++++++++ common/server/client/main.go | 31 +++++++++ common/server/server.go | 67 ++++++++++++++++++ 3 files changed, 225 insertions(+) create mode 100644 common/reflect/main.go create mode 100644 common/server/client/main.go create mode 100644 common/server/server.go diff --git a/common/reflect/main.go b/common/reflect/main.go new file mode 100644 index 0000000..691e7a6 --- /dev/null +++ b/common/reflect/main.go @@ -0,0 +1,127 @@ +package main + +import ( + "fmt" + "reflect" +) + +type User struct { + Name string `json:"name"` + Age int `json:"age" default:"18"` + addr string `json:"addr"` +} + +func (u User) Do(in string) (string, int) { + fmt.Printf("%s Name is %s, Age is %d \n", in, u.Name, u.Age) + return u.Name, u.Age +} + +func main() { + u := User{"tom", 27, "beijing"} + + // 获取对象的 Value + v := reflect.ValueOf(u) + fmt.Println("Value:", v) + // fmt.Printf("%v\n", u) + + // 获取对象的 Type + t := reflect.TypeOf(u) + fmt.Println("Type:", t) + // fmt.Printf("%T\n", u) + + t1 := v.Type() + fmt.Println(t == t1) + + v1 := reflect.New(t) + fmt.Println(v1) + fmt.Println() + + // 获取 Kind 类型 + k := t.Kind() + fmt.Println("Kind:", k) + k1 := v.Kind() + fmt.Println(k == k1) + fmt.Println() + + // 修改反射对象的值 + i := 20 + fmt.Println("before i =", i) + e := reflect.Indirect(reflect.ValueOf(&i)) + // e := reflect.ValueOf(&i).Elem() + if e.CanSet() { + e.SetInt(22) + } + fmt.Println("after i =", i) + fmt.Println() + + // 反射字段操作 + // elem := reflect.Indirect(reflect.ValueOf(&u)) + elem := reflect.ValueOf(&u).Elem() + for i := 0; i < t.NumField(); i++ { + // 反射获取字段的元信息,例如:名称、Tag 等 + ft := t.Field(i) + fmt.Println("field name:", ft.Name) + tag := ft.Tag + fmt.Println("Tag:", tag) + fmt.Println("Tag json:", tag.Get("json")) + + // 反射修改字段的值 + fv := elem.Field(i) + if fv.CanSet() { + if fv.Kind() == reflect.Int { + fmt.Println("change age to 30") + fv.SetInt(30) + } + if fv.Kind() == reflect.String { + fmt.Println("change name to jerry") + fv.SetString("jerry") + } + } + fmt.Println() + } + fmt.Println("after user:", u) + fmt.Println() + + // 反射方法操作 + for i := 0; i < v.NumMethod(); i++ { + method := t.Method(i) // 获取方法信息对象,方法 1 + mt := method.Type // 获取方法信息 Type 对象,方法 1 + + // m := v.Method(i) // 获取方法信息对象,方法 2 + // mt := m.Type() // 获取方法信息 Type 对象,方法 2 + + fmt.Println("method name:", method.Name) + + in := []reflect.Value{} + + // 获取方法入参类型 + for j := 0; j < mt.NumIn(); j++ { + fmt.Println("method in type:", mt.In(j)) + if mt.In(j).Kind() == reflect.String { + in = append(in, reflect.ValueOf("welcome")) + } + // 方法 1 获取的方法信息对象会把方法的接受者也当着入参之一 + if mt.In(j).Name() == t.Name() { + in = append(in, v) + } + } + + // 获取方法返回类型 + for j := 0; j < mt.NumOut(); j++ { + fmt.Println("method out type:", mt.Out(j)) + } + + // 反射方法调用 + // out := m.Call(in) // 方法 1 获取的 Method 对象反射调用方式 + out := method.Func.Call(in) // 方法 1 获取的 Method 对象反射调用方式 + for _, o := range out { + fmt.Println("out:", o) + } + } + fmt.Println() + + // Value 转原始类型 + if u1, ok := v.Interface().(User); ok { + fmt.Println("after:", u1.Name, u1.Age) + } +} diff --git a/common/server/client/main.go b/common/server/client/main.go new file mode 100644 index 0000000..83d2613 --- /dev/null +++ b/common/server/client/main.go @@ -0,0 +1,31 @@ +package main + +import ( + "log" + "net/http" + + "github.com/ehlxr/go-utils/common/server" +) + +func main() { + server := server.NewServer() + err := server.Register(new(Hello)) + if err != nil { + log.Fatal(err) + } + err = server.Start(":8080") + if err != nil { + log.Fatal(err) + } +} + +type Hello struct { +} + +func (h *Hello) Print(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("print")) +} + +func (h *Hello) Hello(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("hello")) +} diff --git a/common/server/server.go b/common/server/server.go new file mode 100644 index 0000000..4921e43 --- /dev/null +++ b/common/server/server.go @@ -0,0 +1,67 @@ +package server + +import ( + "fmt" + "log" + "net/http" + "reflect" + "strings" + "sync" +) + +type Server struct { + name string + val reflect.Value + typ reflect.Type + methods []reflect.Method + lock sync.Mutex +} + +func NewServer() *Server { + server := new(Server) + server.methods = make([]reflect.Method, 0) + return server +} + +func (s *Server) Start(addr string) error { + log.Println(fmt.Sprintf("server start on addr [%s]", addr)) + return http.ListenAndServe(addr, s) +} + +func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { + for _, method := range s.methods { + if strings.ToLower("/"+s.name+"/"+method.Name) == r.URL.Path { + method.Func.Call([]reflect.Value{s.val, reflect.ValueOf(w), reflect.ValueOf(r)}) + } + } +} + +func (s *Server) Register(service interface{}) error { + s.lock.Lock() + defer s.lock.Unlock() + + s.typ = reflect.TypeOf(service) + s.val = reflect.ValueOf(service) + s.name = reflect.Indirect(s.val).Type().Name() + if s.name == "" { + return fmt.Errorf("no service name for type %s", s.typ.String()) + } + for m := 0; m < s.typ.NumMethod(); m++ { + method := s.typ.Method(m) + mtype := method.Type + if mtype.NumIn() != 3 { + return fmt.Errorf("method %s has wrong number of ins: %d", method.Name, mtype.NumIn()) + } + reply := mtype.In(1) + if reply.String() != "http.ResponseWriter" { + return fmt.Errorf("%s argument type not exported: %s", method.Name, reply) + } + arg := mtype.In(2) + if arg.String() != "*http.Request" { + return fmt.Errorf("%s argument type not exported: %s", method.Name, arg) + } + s.methods = append(s.methods, method) + log.Println("registry path:", strings.ToLower("/"+s.name+"/"+method.Name)) + } + return nil +}