轉自:http://blog.manhuahe.net/2012/12/%E4%BD%BF%E7%94%A8go%E8%AF%AD%E8%A8%80%E4%B8%A4%E4%B8%89%E4%BA%8B/
在團隊最近的幾個“隱藏”項目中,都使用了Go語言做為開發語言,Go語言的強大特性給我們的工作帶來了很多便利性與快樂。我想在此以我實際工作中遇到的問題,反觀Go語言在語言特性上給我們帶來的便利性,算是對這段時間學習工作的一個總結吧。
一、channel的使用
在Go里,寫多線程程序變的更簡單了,比如,我們要自己手寫實現個簡單的數據庫連接池,在Java里,我們需要一個數組來存放數據庫連接,連接池的所有操作方法都要對其加上鎖,以確保兩個線程沒有共用一個連接,連接池里沒連接了或連接滿了怎么辦等。然而在Go里,我們只需要一個具有緩沖區的channel就行了:
pool := make(chan mysql.Conn, size) conn := <-p.pool //從連接池取一個連接 p.pool <- conn //在把連接放回連接池
就這三句簡單的代碼組成了實現一個完美支持多線程的數據庫連接池類庫的核心基石,剩下的就是對該類庫功能上的完美封裝與優化了。
二、map的使用
Go語言的map,是將map這種復雜的數據結構做為語言的內置類型來實現的。
oneMap[key] = value //直接賦值 value,ok := oneMap[key] //取一個map的值與判斷該key是否存在一體化完成 for key,value := range oneMap {} //簡單遍歷一個map,取得key與其value delete(oneMap[key]) //刪除一個key,不用擔心該key不存在於map中而報錯
單單以上四項,就不知給我的開發帶來了多少的方便,而且增強了程序的健壯性。
三、json的使用
由於項目中很多地方需要用到使用json文件做為程序的配置文件,因此,解析json數據也是經常做的事,Go語言提供給我們的json庫能讓我們很方便的解析自己想要的json數據,只要定義一個與json文件結構一樣的struct或map就可以了。
json.Unmarshal(jsonbytes, jsonObj) //jsonObj的結構要與數據本身格式一樣
而且,json庫還提供了MarshalJSON接口方法,外部程序只要實現了該接口,就可以自定義生成json數據的方式了。
四、格式化生成字符串
在Go里,使用了fmt.Sprintf()方法,在方法里傳入自己預先定義好的模版,然后按順序傳入自己想往模版里填的數據,就生成自己想要的格式化字符串了。這點尤其適用於我們生成具有固定格式的日志數據,比如:
fmt.Sprintf("[%s] %s %s",time,ip,log)
就能格式化一條形式如:[2012-12-20] 127.0.0.1 LOG_CONTENT 的日志,很方便有木有。
五、自定義類型的使用
有一次自己想實現一套類似這樣的機制,就是所有方法名放在一個配置文件里,然后在運行時可以根據命令行指定方法名執行相應的實現方法,按以前的思路,是要實現一套工廠模式的代碼,但在Go里,一個map就搞定了:
type CreatorImpl func() ICreater var funcmap = map[string]CreatorImpl{"Method1": Method1Impl, "Method2": Method2Impl} funcmap[builder]() //builder為外部傳入的參數,執行指定的方法 func Method1Impl() ICreater { //實現1 } func Method2Impl() ICreater { //實現2 }
將方法的聲明定義為一個類型CreatorImpl,將CreatorImpl做為一個map的值類型生成一個map,實現一個類似工廠模式功能的代碼就這么簡單。
六、反射的使用
反射是把雙刃劍,在Go中,使用反射倒也沒有覺得比其他語言有更優秀,但對於特定應用場景,適當的使用反射,能讓我們的程序更優雅和簡潔,附上一段我在項目中統一判斷具有不同類型和結構的對象里的屬性是否包含空串的代碼:
logvalue := reflect.ValueOf(log).Elem() islegal := true for i := 1; i < logvalue.NumField(); i++ { f := logvalue.Field(i) str := fmt.Sprintf("%v", f.Interface()) islegal = (str != "") if !islegal { return islegal } }
七、嚴格的編譯
Go代碼的編譯器能讓你在編譯的時候就修正一切可能帶來錯誤和垃圾代碼的代碼,比如引入的包、聲明的變量在程序中沒有使用到,會編譯錯誤;不小心調用了錯誤的方法等等。剩下的錯誤就是代碼本身邏輯的錯誤了,這些都給日常開發帶來了非常大的方便。
八、其他
還有優雅而明確的變量聲明方式,方便的單元測試go test,容易處理的error,時刻保證資源釋放的defer語句,報錯panic函數,恢復recover函數。對了,結合panic和recover方法,再依靠Go本身的系統庫,可以實現一個類似Java中的異常棧信息,輸出從引發panic到執行recover過程中所經歷的所有方法調用與所在行號。這點在錯誤日志記錄中尤為有用。
很喜歡使用Go開發項目,我相信Go語言會越來越被世人所接受和熟知,並加以應用,發展的越來越好!