nject 是依賴注入的Go語言實現,它能在運行時注入參數,調用方法,是 Martini 框架(Go語言中著名的 Web 框架)的基礎核心。git
demo1:github
package main import ( "fmt" "github.com/codegangsta/inject" ) type S1 interface{} type S2 interface{} func Format(name string, company S1, level S2, age int) { fmt.Printf("name = %s, company=%s, level=%s, age = %d!\n", name, company, level, age) } func main() { //控制實例的建立 inj := inject.New() //實參注入 inj.Map("tom") inj.MapTo("tencent", (*S1)(nil)) inj.MapTo("T4", (*S2)(nil)) inj.Map(23) //函數反轉調用 inj.Invoke(Format) }
可見 inject 提供了一種注入參數調用函數的通用功能,inject.New() 至關於建立了一個控制實例,由其來實現對函數的注入調用。inject 包不但提供了對函數的注入,還實現了對 struct 類型的注入,Apply 方法是用於對 struct 的字段進行注入,參數爲指向底層類型爲結構體的指針。可注入的前提是:字段必須是導出的(也即字段名以大寫字母開頭),而且此字段的 tag 設置爲`inject`
。示例代碼以下所示框架
package main import ( "fmt" "github.com/codegangsta/inject" ) type S1 interface{} type S2 interface{} type Staff struct { Name string `inject` Company S1 `inject` Level S2 `inject` Age int `inject` } func main() { //建立被注入實例 s := Staff{} //控制實例的建立 inj := inject.New() //初始化注入值 inj.Map("tom") inj.MapTo("tencent", (*S1)(nil)) inj.MapTo("T4", (*S2)(nil)) inj.Map(23) //實現對 struct 注入 inj.Apply(&s) //打印結果 fmt.Printf("s = %v\n", s) }
另外 Injector 還規定了 SetParent 行爲,它用於設置父 Injector,其實它至關於查找繼承。也即經過 Get 方法在獲取被注入參數時會一直追溯到 parent,這是個遞歸過程,直到查找到參數或爲 nil 終止函數
Map 和 MapTo 方法都用於注入參數,保存於 injector 的成員 values 中。這兩個方法的功能徹底相同,惟一的區別就是 Map 方法用參數值自己的類型當鍵,而 MapTo 方法有一個額外的參數能夠指定特定的類型當鍵。可是 MapTo 方法的第二個參數 ifacePtr 必須是接口指針類型,由於最終 ifacePtr 會做爲 InterfaceOf 方法的參數。
爲何須要有 MapTo 方法?由於注入的參數是存儲在一個以類型爲鍵的 map 中,可想而知,當一個函數中有一個以上的參數的類型是同樣時,後執行 Map 進行注入的參數將會覆蓋前一個經過 Map 注入的參數。
SetParent 方法用於給某個 Injector 指定父 Injector。Get 方法經過 reflect.Type 從 injector 的 values 成員中取出對應的值,它可能會檢查是否設置了 parent,直到找到或返回無效的值,最後 Get 方法的返回值會通過 IsValid 方法的校驗。spa
demo3:指針
package main import ( "fmt" "github.com/codegangsta/inject" ) type SpecialString interface{} func Say(name string, gender SpecialString, age int) { fmt.Printf("My name is %s, gender is %s, age is %d!\n", name, gender, age) } /* func Say(name string, gender string, age int) { fmt.Printf("My name is %s, gender is %s, age is %d!\n", name, gender, age) } */ //沒有定義 SpecialString 接口做爲 gender 參數的類型,而把 name 和 gender 都定義爲 string 類型,那麼 gender 會覆蓋 name 的值 func main() { inj := inject.New() inj.Map("張三") inj.MapTo("男", (*SpecialString)(nil)) //inj.Map("男") inj2 := inject.New() inj2.Map(25) inj.SetParent(inj2) inj.Invoke(Say) }