1、接口node
1.什麼是interfacegolang
在面向對象編程中,能夠這麼說:「接口定義了對象的行爲」, 那麼具體的實現行爲就取決於對象了。算法
在Go中,接口是一組方法簽名。當一個類型爲接口中的全部方法提供定義時,它被稱爲實現該接口。它與oop很是類似。接口指定類型應具備的方法,類型決定如何實現這些方法。編程
2.定義app
Interface類型能夠定義一組方法,可是這些不須要實現,而且interface不能包含任何變量負載均衡
type 標識符 interface{ Method1(參數列表) 返回值列表 Method2(參數列表) 返回值列表 ... }
3.接口的實現dom
golang中的接口,不須要顯式的實現,只要一個變量,含有接口類型中的全部方法,那麼這個變量就實現這個接口。所以,golang中沒有implement相似的關鍵字ide
若是一個變量含有多個interface類型的方法,那麼這個變量就實現了多個接口
若是一個變量只含有一個interface的部分方法,那麼這個變量沒有實現這個函數
package main import "fmt" //定義一個薪資計算的接口,該接口有CalculateSalary方法,並無具體實現,只是一種規範 type SalaryCalculate interface{ CalculateSalary() int } type Manager struct{ basicpay int bonus int } type General struct{ basicpay int } //類型去具體實現接口中的方法 func (this Manager) CalculateSalary() int{ return this.basicpay + this.bonus } func (this General) CalculateSalary() int{ return this.basicpay } func totalExpense(p []SalaryCalculate){ total := 0 for _, v := range p{ //使用者不須要關心底層,只須要調用接口 total += v.CalculateSalary() } fmt.Printf("總開支 %d", total) } func main(){ Manager1 := Manager{10000, 6000} Manager2 := Manager{8000,7500} General1 := General{5000} //值類型實現接口 employees := []SalaryCalculate{Manager1, Manager2, General1} totalExpense(employees) }
4.多態:一種事物的多種形態,均可以按照統一的接口進行操做oop
例如:咱們定義一個車的接口,該接口擁有各類車共同擁有的方法,而該接口能夠表明各類車,咱們只須要讓具體的車去實現這個接口。
例如:Linux中的一切皆文件的思想,不管是磁盤,內存,仍是...都是文件,咱們只須要定義一個操做文件的接口,而各個具體的東西去實現接口的方法,在調用的時候只須要經過接口進行操做
例如:GO中sort包下Sort方法爲咱們提供了排序的原語,咱們只須要去實現接口的方法便可,該包具備很強的擴展性,不須要爲每一個類型都定義一個方法,只須要提供一個排序的接口,而對於使用者也是友好的,咱們不須要去記住每一個類型所應該對應的排序方法。
type Interface interface { // Len is the number of elements in the collection. // Len 爲集合內元素的總數 Len() int // Less reports whether the element with // index i should sort before the element with index j. // // Less 返回索引爲 i 的元素是否應排在索引爲 j 的元素以前。 Less(i, j int) bool // Swap swaps the elements with indexes i and j. // Swap 交換索引爲 i 和 j 的元素 Swap(i, j int) } package main import ( "sort" "fmt" "math/rand" ) type Student struct{ ID string Name string } type StudentArry []Student func (this StudentArry) Len() int{ return len(this) } func (this StudentArry) Less(i, j int) bool{ return this[i].Name < this[j].Name } func (this StudentArry) Swap(i, j int){ this[i], this[j] = this[j], this[i] } func trans(n StudentArry){ for _, v := range n{ fmt.Println(v) } } func main(){ var stus StudentArry for i := 0; i < 10; i++{ stu := Student{ ID: fmt.Sprintf("154%d", rand.Int()), Name: fmt.Sprintf("stu%d", rand.Intn(100)), } stus = append(stus,stu) } trans(stus) fmt.Printf("\n") sort.Sort(stus) trans(stus) }
5.接口嵌套
package main import "fmt" type Read interface{ Read() } type Write interface{ Write() } type ReadWrite interface{ Read Write } type File struct{ } func (this File) Read(){ fmt.Println("read data") } func (this File) Write(){ fmt.Println("write data") } func Test(v ReadWrite)(){ v.Read() v.Write() } func main(){ var f File Test(f) }
6.空接口,interface{}
空接口沒有任何方法,因此全部類型都實現了空接口,也就是任何變量均可以賦值給空接口
var a int var b interface{} b = a
判斷一個變量是否實現了指定接口
if sv, ok := v.(Stringer); ok{ fmt.Println("ok") }
7.類型斷言,因爲接口是通常類型,不知道具體類型,若是要轉成具體類型,能夠採用如下方法進行轉換
var t int var x inteface{} x = t y = x.(int) //轉成int
package main import "fmt" type Student struct{ Name string } func CheckType(items ...interface{}){ for _, v := range items{ switch v.(type) { case bool: fmt.Printf("%v params is bool\n", v) case int: fmt.Printf("%v params is int\n", v) case Student: fmt.Printf("%v params is Studen\nt", v) case *Student: fmt.Printf("%v params is *Student\n", v) } } } func main(){ stu := Student{ Name: "bob", } CheckType(false, 1, stu, &stu) }
實現一個通用的鏈表類
//link.go package main import "fmt" type Node struct{ Data interface{} Next *Node } type Link struct{ Head *Node Tail *Node } func (this *Link) IsEmpty() bool{ return this.Head == nil } func (this *Link) Init(node *Node){ this.Head = node this.Tail = node } func (this *Link) Insert(data interface{}){ node := &Node{ Data: data, } if this.IsEmpty(){ this.Init(node) return } node.Next = this.Head this.Head = node } func (this *Link) Trans(){ cur := this.Head for cur != nil{ fmt.Println(cur.Data) cur = cur.Next } } func (this *Link) Append(data interface{}){ node := &Node{ Data: data, } if this.IsEmpty(){ this.Init(node) return } this.Tail.Next = node this.Tail = node } //main.go package main import "fmt" func main(){ var link Link for i := 0; i < 10; i++{ link.Insert(fmt.Sprintf("stu%d",i)) } for i := 0; i < 10; i++{ link.Append(fmt.Sprintf("stu%d",i)) } link.Trans() }
變量slice和接口slice之間的賦值操做,for range
2、反射
能夠在運行時動態獲取變量的相關信息
1.兩個函數
reflect.TypeOf,獲取變量的類型,返回reflect.Type類型
reflect.ValueOf,獲取變量的值,返回reflect.Value類型
import ( "fmt" "reflect" ) type Student struct{ Name string Age int Score float32 } func Test(n interface{}){ a := reflect.TypeOf(n) fmt.Println(a) v := reflect.ValueOf(n) fmt.Println(v) fmt.Printf("a type is %T; v type is %T",a, v) } func main(){ var stu Student Test(stu) } /* main.Student { 0 0} a type is *reflect.rtype; v type is reflect.Value */
經過reflect.Value類型咱們能夠分析變量的各類屬性
其中,reflect.Value.Kind,獲取變量的類別,返回一個常量
const ( Invalid Kind = iota Bool Int Int8 Int16 Int32 Int64 Uint Uint8 Uint16 Uint32 Uint64 Uintptr Float32 Float64 Complex64 Complex128 Array Chan Func Interface Map Ptr Slice String Struct UnsafePointer )
type Student struct{ Name string Age int Score float32 } func Test(n interface{}){ a := reflect.TypeOf(n) fmt.Println(a) v := reflect.ValueOf(n) k := v.Kind() fmt.Println(k) } func main(){ var stu Student Test(stu) } /* main.Student struct 能夠看出stu這個變量的類型是main包下的Student 而其類別是結構體 */
固然咱們也能夠將reflect.Value類型逆轉成interface{}類型
reflect.Value.Interface() //轉換成interface{}類型
其轉換關係爲
變量 <------> interface{} <------> reflect.Value
獲取變量的值
reflect.ValueOf(x).Float()
reflect.ValueOf(x).Int()
reflect.ValueOf(x).String()
reflect.ValueOf(x).Bool()
經過反射來改變變量的值
type Student struct{ Name string Age int Score float32 } func Test(n interface{}){ v := reflect.ValueOf(n) //注意v是指針類型,因此須要經過Elem()轉換,其本質和*v同樣 v.Elem().SetInt(99) } func main(){ b := 100 //注意得傳指針類型,若是傳值類型會panic Test(&b) fmt.Println(b) }
用反射操做結構體
reflect.Value.NumField() 獲取結構體中字段的個數
reflect.Value.NumMethod() 獲取結構體方法的個數
reflect.Value.Method(n).Call 來調用結構體中的方法
package main import ( "fmt" "reflect" ) type Student struct{ Name string Age int Score float32 } func (this Student) Print(){ fmt.Println(this) } func Test(p interface{}){ val := reflect.ValueOf(p) if val.Kind() != reflect.Struct{ fmt.Println("expect struct") return } fieldNum := val.NumField() methodNum := val.NumMethod() fmt.Println(fieldNum, methodNum) //調用第幾個方法 val.Method(0).Call(nil) } func main(){ stu := Student{ Name: "stu100", Age: 18, Score: 99.5, } Test(stu) }
接口實例
實現一個負載均衡調度算法,支持隨機、輪訓等,思考如何實現如內置sort.Sort()同樣,支持第三方擴展的需求
//balance.go /* 定義一個負載均衡算法接口,該接口接收一個包含主機實例的切片,經過算法返回一個主機實例 */ package balance type Balancer interface{ DoBalance([] *Instance) (*Instance, error) } //instance.go /*主機實例*/ package balance import "strconv" type Instance struct{ host string port int } //工廠函數 func NewInstance(host string, port int) *Instance{ return &Instance{ host: host, port: port, } } func (this *Instance) GetHost() string{ return this.host } func (this *Instance) GetPort() int{ return this.port } func (this *Instance) String() string{ return this.host + ":" + strconv.Itoa(this.port) } //random.go /* 咱們寫一個包內置的隨機算法,經過init函數進行初始化註冊,該算法實現了負載均衡算法接口 */ package balance import ( "errors" "math/rand" ) type RandomBalance struct{ } func init(){ RegisterBalance("random", &RandomBalance{}) } func (this *RandomBalance) DoBalance(insts [] *Instance) (inst *Instance,err error){ lens := len(insts) if lens == 0{ err = errors.New("no instance") return } index := rand.Intn(lens) inst = insts[index] return } //mgr.go /* 一個註冊中心,擁有註冊過的算法(不管是咱們內置的仍是用戶擴展的), */ package balance import "fmt" type BalanceMgr struct{ allBalancer map[string]Balancer } var mgr = BalanceMgr{ allBalancer: make(map[string]Balancer), } func (this *BalanceMgr) registerBalance(name string,b Balancer){ this.allBalancer[name] = b } func RegisterBalance(name string,b Balancer){ mgr.registerBalance(name, b) } func DoBalance(name string, insts []*Instance) (inst *Instance, err error){ balancer, ok := mgr.allBalancer[name] if !ok{ err = fmt.Errorf("Not found %s banlancer", name) return } inst, err = balancer.DoBalance(insts) return }
//poll.go /* 看成用戶擴展的算法,實現負載均衡算法接口,並在註冊中心註冊 */ package main import ( "go_dev/day06/t9/balance" "errors" ) type PollBalance struct{ ctn int } func init(){ balance.RegisterBalance("poll", &PollBalance{}) } func (this *PollBalance) DoBalance(insts [] *balance.Instance) (inst *balance.Instance,err error) { lens := len(insts) if lens == 0{ err = errors.New("No instance") return } this.ctn = (this.ctn + 1) % lens inst = insts[this.ctn] return } //main.go package main import ( "time" "fmt" "math/rand" "go_dev/day06/t9/balance" "os" ) func main() { var insts []*balance.Instance for i := 0; i < 16; i++{ host := fmt.Sprintf("192.168.%d.%d",rand.Intn(255),rand.Intn(255)) one := balance.NewInstance(host, 8080 ) insts = append(insts, one) } //能夠寫到配置文件中 var balanceName = "random" if len(os.Args) > 1{ balanceName = os.Args[1] } for { inst, err := balance.DoBalance(balanceName, insts) if err != nil{ fmt.Println(err) continue } fmt.Println(inst) time.Sleep(time.Second) } }