当发现go语言没有类时,小伙伴都震惊了,但是如果你要保证好的代码结构与内部逻辑组织结构,类这种模式貌似又是不可或缺的
那么问题来了,go语言有没有办法来模拟类操作呢?答案是肯定的

首先我们来看go语言struct数据类型

type Godeye struct {   

     name string   

     age int   

 }

初始化

p := Godeye{"godeye", 28}  //有序   

 p := Godeye{age:28}        //无序


最有意思的是,struct可以增加关联函数

func funcName(varName1 typeName2[,varName2 typeName2, ...]) typeName {...}

例子

func (this Godeye) Test(area string) string { 

     return *this.name + area 

 }


其中Godeye就是对应的Godeye struct而this.name就是Godeye中的name

有没有发现,和类何其的相似,在一个go文件里,可以定义一个struct,name age相当于类里的变量
Test相当于类里的方法

但是光模拟是没有用的,我们该怎么调用呢?
类调用很简单,直接用classname->Test()直接调用类对应的方法
go语言就不同,甚至可以说复杂多,首先你要先理解reflect反射的概念,其次还要熟悉interface,再次还要理解new make是怎么运作的

reflect反射:调用的关键
反射就是动态运行时的状态。对应的包是reflect包
i在这里是一个struct,转化为reflect对象
t := reflect.TypeOf(i)    //得到类型的元数据,通过t我们能获取类型定义里面的所有元素
v := reflect.ValueOf(i)   //得到实际的值,通过v我们获取存储在里面的值,还可以去改变值
转化为reflect对象之后我们就可以进行一些操作了,也就是将reflect对象转化成相应的值,例如
tag := t.Elem().Field(0).Tag        //获取定义在struct里面的标签
name := v.Elem().Field(0).String()  //获取存储在第一个字段里面的值

interface:函数的参数
简单的说,interface是一组method的组合,我们通过interface来定义对象的一组行为
我们可以通过定义interface参数,让函数接受各种类型的参数

还是用一个可运行的完整例子来说明:
1.新建一个main.go

package main 


 import ( 

     "./action" 

     "fmt" 

     "log" 

     "net/http" 

     "net/url" 

     "reflect" 

 ) 


 func main() { 

     http.HandleFunc("/index", do) 

     err := http.ListenAndServe(":8080", nil) 

     if err != nil { 

             log.Fatal("listenAndServer: ", err) 

     } 

 } 


 func do(w http.ResponseWriter, r *http.Request) { 

     r.ParseForm() 

     m, a := r.PostFormValue("m"), r.PostFormValue("a") 

     queryForm, err := url.ParseQuery(r.URL.RawQuery) 

     if err == nil && len(queryForm["m"]) > 0 { 

         m = queryForm["m"][0] 

     } 

     if err == nil && len(queryForm["a"]) > 0 { 

         a = queryForm["a"][0] 

     } 


     //创建实例 

     conf := action.Conf{} 

     conf.Op = &m 


     //值信息 

     v := reflect.ValueOf(conf) 

     callMethod(&v, m, []interface{}{a}) 

 } 


 func callMethod(v *reflect.Value, method string, params []interface{}) { 

     //字符串方法调用,且能找到实例属性.Op 

     f := (*v).MethodByName(method) 

     if f.IsValid() { 

         args := make([]reflect.Value, len(params)) 

         for k, param := range params { 

             args[k] = reflect.ValueOf(param) 

         } 

         //调用 

         ret := f.Call(args) 

         if ret[0].Kind() == reflect.String { 

             fmt.Printf("%s Call result: %s\n", method, ret[0].String()) 

         } 

     } else { 

         fmt.Println("can't call " + method) 

     } 

 }


2.在main.go的同一级目录创建action文件夹,里面加入action.go文件

package action 


 type Conf struct { 

     Op       *string `json:"jsonop" xml:"xmlOpName"` 

 } 


 func (this Conf) Test(name string) string { 

     return *this.Op + name 

 }


3.编译运行,然后浏览器输入 http://localhost:8080/index?m=Test&a=b

查看输出结果