go語言中使用反射函數代替switch文法

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

近期在公司實習,參與了公司的一個分布式的應用服務系統。系統採用Golang語言作為系統的開發語言,在開發過程中採用了Go語言的反射函數的特性來取代了以前常使用的switch文法。

switch-case是一種多種選擇的文法,其本質與if-else方法差不多,都是通過判斷條件來執行不同的方法。而Go提供了一種機制在運行時更新變數和檢查它們的值,調用它們的方法,和它們支援的內在操作,但是在編譯時間並不知道這些變數的類型。這種機制被稱為反射,反射也可以讓我們將類型本身作為第一類的實值型別處理。

Web應用路由問題

在我們編寫Web應用過程中,常常會遇到一個路由需要對應一個方法,我們會選擇使用switch的方法來進行路由的匹配,若是路由匹配成功,我們會調用一個方法,這種方法能夠很簡便的完成我們的工作,也便於程式員在編寫代碼過程中釐清思路。

問題:

在一個URL的路由中,我們在request中通過cmd的參數來對應一個方法,這樣我們要如何根據一個cmd對應一個方法?

可能針對這個問題有人會說,我們為什麼不把cmd放到URL裡面,這樣的話就是一個方法對應一個路由,而且大多數的Web架構會通過回呼函數來進行函數調用,針對於這個問題,我只能說大部分的都是將cmd放到http的request裡面的,具體的好處可能就是減少了對API的監管,以及當路由比較多的時間能夠減少麻煩吧。

用switch方法實現:

cmd := this.GetString("cmd")switch cmd{  case "ls":    ls()  case "cd":    cd()  default:    fmt.Println("cmd method missing")}

上述的方法先通過URL的參數擷取到cmd,然後通過cmd來調用相對應的方法。在傳統的MVC的設計模式中,需要在Controller中添加switch方法,同時需要在Model中實現相對應的方法,總計修改了2個檔案。

go語言反射函數

reflect包

在reflect包中,主要通過Typeof()和Valueof()兩個方法來實現反射。兩個方法相互結合,能夠反射出被反射函數的全部資訊。

package mainimport (    "fmt"    "reflect")type Ref struct {       id int     name string}func (ref *Ref)GetName(){       fmt.Println("getName()函數")}func (ref *Ref)GetNameById(){    fmt.Println("getNameById()函數")}func main(){    t := reflect.TypeOf(&Ref{})    v := reflect.ValueOf(new(Ref))    fmt.Println(t)    fmt.Println(v)    for i:= 0; i< t.NumMethod();i++{        fmt.Println(t.Method(i).Name)        v.Method(i).Call(nil)    }}

TypeOf()

TypeOf()函數主要是列印出被反射函數的類型,其返回結果是reflect.Type類型。

在上面的樣本中,通過Method().Name能夠反射其方法的函數名。

常用的方法:

  • func (t *rtype)String() string
  • func (t *rtype)Name() string
  • func (t *rtype)Kind() reflect.kind
  • func (t *rtype)Method(int) reflect.Method
  • func (t *rtype)Elem() reflect.Type
  • func (t *rtype)In(int) reflect.Type

ValueOf()

ValueOf()函數主要是列印出被反射函數的類型,其返回結果是reflect.Value類型。

在上面的樣本中,通過Method().Call()能夠反射出其函數並執行。

常用的方法:

  • func (v Value)String() string
  • func (v Value)Elem() reflect.Value
  • func (v Value)Method(int) reflect.Value
  • func (v Value)Call(in []Value) (r []Value)

反射的實現過程

由於有反射的存在,因此在傳統的MVC的設計模式中,當我們添加服務時,不需要修改Controller端的代碼,Controller只需要維持一個map的表,裡面的就來儲存需要被反射的models。

package server import(  "reflect"  "fmt")// ReServer 來儲存map的結構體type ReServer struct {  m map[string]interface{}}// RegisterService 註冊服務func (this *ReServer)RegisterService(service interface{})(err error){  serviceType := reflect.TypeOf(service).Elem()  ServiceName := serviceType.Name()  if _,ok := this.m[ServiceName]  if ok {    fmt.Println("service has been registered")  }else{    this.m[ServiceName] = service  }  return}//  Start 服務啟動func (this *ReServer)Start(){  for k,v := range this.m {    // 裡面根據商務邏輯執行想要的方法  }}

在上訴的例子中,通過對services的服務註冊,就能夠通過Start()函數探索服務,並且根據業務來實現自己的代碼。

package mainimport (  "server")type Server struct {}func (server *Server)funOne(){  fmt.Println("Server FunOne")} func main(){  reServer := &server.ReServer{    m: make(map[string]interface{})  }  err := reServer.RegisterService(new(Server))  reServer.Start()}

因此在我們主函數中,匯入封裝好的包,只需要註冊一個結構體,就能夠將自己的方法反射出來實現。

對應上面的Web的路由問題,我們將Controller進行封裝,然後將Model進行反射,當我們業務增加時,我們在Model裡面添加就可以了,不需要修改Controller。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.