Go语言系列- 接口和反射
接口
1. 定义: Interface类型可以定义一组方法,但是这些不需要实现。并且interface不能包含任何变量。
type example interface{ Method1(参数列表) 返回值列表 Method2(参数列表) 返回值列表 }
2.interface类型默认是一个指针
type example interface{ Method1(参数列表) 返回值列表 Method2(参数列表) 返回值列表 … } var a example a.Method1()
3. 接口实现
- a. Golang中的接口,不需要显示的实现。只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。因此,golang中没有implement类似的关键字
- b. 如果一个变量含有了多个interface类型的方法,那么这个变量就实现了多个接口。
- c. 如果一个变量只含有了1个interface的方部分方法,那么这个变量没有实现这个接口。
package main import "fmt" type Car interface { GetName() string Run() DiDi() } type Test interface { Hello() } type BMW struct { Name string } func (p *BMW) GetName() string { return p.Name } func (p *BMW) Run() { fmt.Printf("%s is running\n", p.Name) } func (p *BMW) DiDi() { fmt.Printf("%s is didi\n", p.Name) } func (p *BMW) Hello() { fmt.Printf("%s is hello\n", p.Name) } type BYD struct { Name string } func (p *BYD) GetName() string { return p.Name } func (p *BYD) Run() { fmt.Printf("%s is running\n", p.Name) } func (p *BYD) DiDi() { fmt.Printf("%s is didi\n", p.Name) } func main() { var car Car var test Test fmt.Println(car) // var bwm = BMW{} // bwm.Name = "宝马" bwm := &BMW{ Name: "宝马", } car = bwm car.Run() test = bwm test.Hello() byd := &BMW{ Name: "比亚迪", } car = byd car.Run() // var a interface{} // var b int // var c float32 // a = b // a = c // fmt.Printf("type of a %T\n", a) }
4.多态:一种事物的多种形态,都可以按照统一的接口进行操作
sort排序
package main import ( "fmt" "math/rand" "sort" ) type Student struct { Name string Id string Age int } type Book struct { Name string Author string } type StudentArray []Student func (self StudentArray) Len() int { return len(self) } func (self StudentArray) Less(i, j int) bool { return self[i].Name > self[j].Name } func (self StudentArray) Swap(i, j int) { self[i], self[j] = self[j], self[i] } func main() { var stus StudentArray for i := 0; i < 10; i++ { stu := Student{ Name: fmt.Sprintf("stu%d", rand.Intn(100)), Id: fmt.Sprintf("110%d", rand.Int()), Age: rand.Intn(100), } stus = append(stus, stu) } for _, v := range stus { fmt.Println(v) } fmt.Println() sort.Sort(stus) for _, v := range stus { fmt.Println(v) } }
5. 接口嵌套:一个接口可以嵌套在另外的接口,如下所示:
type ReadWrite interface { Read(b Buffer) bool Write(b Buffer) bool } type Lock interface { Lock() Unlock() } type File interface { ReadWrite Lock Close() }
package main import "fmt" type Reader interface { Read() } type Writer interface { Write() } type ReadWriter interface { Reader Writer } type File struct { } func (self *File) Read() { fmt.Println("read data") } func (self *File) Write() { fmt.Println("write data") } func Test(rw ReadWriter) { rw.Read() rw.Write() } func main() { var f *File var b interface{} b = f // Test(f) v, ok := b.(ReadWriter) fmt.Println(v, ok) }
6. 类型断言,由于接口是一般类型,不知道具体类型,如果要转成具体类型,可以采用以下方法进行转换:
var t int var x interface{} x = t y, ok = x.(int) //转成int,带检查
7. 练习,写一个函数判断传入参数的类型
package main import ( "fmt" ) type Studnet struct { Name string Sex string } func Test(a interface{}) { // b, ok := a.(int) b, ok := a.(Studnet) if ok == false { fmt.Println("convert failed") return } // b += 3 fmt.Println(b) } func just(items ...interface{}) { for index, v := range items { switch v.(type) { case bool: fmt.Printf("%d params is bool, value is %v\n", index, v) case int, int32, int64: fmt.Printf("%d params is int, value is %v\n", index, v) case float32, float64: fmt.Printf("%d params is float, value is %v\n", index, v) case string: fmt.Printf("%d params is string, value is %v\n", index, v) case Studnet: fmt.Printf("%d params is student, value is %v\n", index, v) case *Studnet: fmt.Printf("%d params is *student, value is %v\n", index, v) } } } func main() { var a interface{} var b int Test(b) a = b c := a.(int) fmt.Printf("%d %T\n", a, a) fmt.Printf("%d %T\n", c, c) var d Studnet = Studnet{ Name: "stu1", Sex: "female", } Test(d) just(28, 8.2, "this is a test", d, &d) }
8. 类型断言,采用type switch方式
9. 空接口.interface{}
空接口没有任何方法,所以所有类型都实现了空接口。
var a int var b interface{} b = a
10.判断一个变量是否实现了指定接口
type Stringer interface { String() string } var v MyStruct if sv, ok := v.(Stringer); ok { fmt.Printf(“v implements String(): %s\n”, sv.String()); }
11. 实现一个通用的链表类
link.go
package main import ( "fmt" ) type LinkNode struct { data interface{} next *LinkNode } type Link struct { head *LinkNode tail *LinkNode } func (p *Link) InsertHead(data interface{}) { node := &LinkNode{ data: data, next: nil, } if p.tail == nil && p.head == nil { p.tail = node p.head = node return } node.next = p.head p.head = node } func (p *Link) InsertTail(data interface{}) { node := &LinkNode{ data: data, next: nil, } if p.tail == nil && p.head == nil { p.tail = node p.head = node return } p.tail.next = node p.tail = node } func (p *Link) Trans() { q := p.head for q != nil { fmt.Println(q.data) q = q.next } }
main.go
package main func main() { var initLink Link for i := 0; i < 10; i++ { // initLink.InsertHead(i) initLink.InsertTail(i) } initLink.Trans() }
12. interface{},接口中一个方法也没有,所以任何类型都实现了空接口,也就是任何变量都可以赋值给空接口。
var a int var b interface{} b = a
13. 变量slice和接口slice之间赋值操作,for range
var a []int var b []interface{} b = a
14. 实现一个负载均衡调度算法,支持随机、轮训等算法
- balance
package balance type Balancer interface { DoBalance([]*Instance, ...string) (*Instance, error) }
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 (p *Instance) GetHost() string { return p.host } func (p *Instance) GetPort() int { return p.port } func (p *Instance) String() string { return p.host + ":" + strconv.Itoa(p.port) }
package balance import "fmt" type BalanceMgr struct { allBalancer map[string]Balancer } var mgr = BalanceMgr{ allBalancer: make(map[string]Balancer), } func (p *BalanceMgr) RegisterBalancer(name string, b Balancer) { p.allBalancer[name] = b } func RegisterBalancer(name string, b Balancer) { mgr.RegisterBalancer(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 balancer", name) return } fmt.Printf("use %s balance\n", name) inst, err = balancer.DoBalance(insts) return }
package balance import ( "errors" "math/rand" ) func init() { RegisterBalancer("random", &RandomBalance{}) } type RandomBalance struct { } func (p *RandomBalance) DoBalance(insts []*Instance, key ...string) (inst *Instance, err error) { if len(insts) == 0 { err = errors.New("No instance") return } lens := len(insts) index := rand.Intn(lens) inst = insts[index] return }
package balance import ( "errors" ) func init() { RegisterBalancer("roundrobin", &RoundRobinBalance{}) } type RoundRobinBalance struct { curIndex int } func (p *RoundRobinBalance) DoBalance(insts []*Instance, key ...string) (inst *Instance, err error) { if len(insts) == 0 { err = errors.New("No instance") return } lens := len(insts) if p.curIndex >= lens { p.curIndex = 0 } inst = insts[p.curIndex] p.curIndex = (p.curIndex + 1) % lens return }
- main
package main import ( "fmt" "go_dev/day7/example/example1/balance" "hash/crc32" "math/rand" ) type HashBalance struct { } func init() { balance.RegisterBalancer("hash", &HashBalance{}) } func (p *HashBalance) DoBalance(insts []*balance.Instance, key ...string) (inst *balance.Instance, err error) { var defkey string = fmt.Sprintf("%d", rand.Int()) if len(key) > 0 { // err := fmt.Errorf("hash balance must pass the hash key") defkey = key[0] } lens := len(insts) if lens == 0 { err = fmt.Errorf("No backend instance") return } crcTable := crc32.MakeTable(crc32.IEEE) hashVal := crc32.Checksum([]byte(defkey), crcTable) index := int(hashVal) % lens inst = insts[index] return }
package main import ( "fmt" "go_dev/day7/example/example1/balance" "math/rand" "os" "time" ) func main() { // 定义一个空切片 // insts := main([]*balance.Instance) 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] } // var balancer balance.Balancer // var conf = "random" // if len(os.Args) > 1 { // conf = os.Args[1] // } // if conf == "random" { // balancer = &balance.RandomBalance{} // 随机 // fmt.Println("use random balancer") // } else if conf == "roundrobin" { // balancer = &balance.RoundRobinBalance{} // 轮询 // fmt.Println("use roundrobin balancer") // } // balancer := &balance.RandomBalance{} // 随机 // balancer := &balance.RoundRobinBalance{} // 轮询 for { inst, err := balance.DoBalance(balanceName, insts) if err != nil { // fmt.Println("do balance err:", err) fmt.Fprintf(os.Stdout, "do balance error\n") continue } fmt.Println(inst) time.Sleep(time.Second) } } // 运行 // go run go_dev/day7/example/example1/main random // go run go_dev/day7/example/example1/main roundrobin // go run go_dev/day7/example/example1/main hash // 编译 // go build go_dev/day7/example/example1/main
反射
1. 反射:可以在运行时动态获取变量的相关信息
Import (“reflect”)
两个函数:
- a. reflect.TypeOf,获取变量的类型,返回reflect.Type类型
- b. reflect.ValueOf,获取变量的值,返回reflect.Value类型
- c. reflect.Value.Kind,获取变量的类别,返回一个常量
- d. reflect.Value.Interface(),转换成interface{}类型
2. reflect.Value.Kind()方法返回的常量
3. 获取变量的值:
reflect.ValueOf(x).Float() reflect.ValueOf(x).Int() reflect.ValueOf(x).String() reflect.ValueOf(x).Bool()
4. 通过反射的来改变变量的值
reflect.Value.SetXX相关方法,比如: reflect.Value.SetFloat(),设置浮点数 reflect.Value.SetInt(),设置整数 reflect.Value.SetString(),设置字符串
5. 用反射操作结构体
a. reflect.Value.NumField()获取结构体中字段的个数 b. reflect.Value.Method(n).Call来调用结构体中的方法
6.案例
package main import ( "fmt" "reflect" ) type Student struct { Name string Age int Score float32 } func test(b interface{}) { t := reflect.TypeOf(b) fmt.Println(t) v := reflect.ValueOf(b) k := v.Kind() fmt.Println(k) iv := v.Interface() stu, ok := iv.(Student) if ok { fmt.Printf("%v %T\n", stu, stu) } } func testInt(b interface{}) { val := reflect.ValueOf(b) val.Elem().SetInt(100) c := val.Elem().Int() fmt.Printf("get value interface{} %d\n", c) fmt.Printf("string value: %d\n", val.Elem().Int()) } func main() { var a Student = Student{ Name: "stu1", Age: 18, Score: 92, } test(a) var b int = 1 testInt(&b) fmt.Println(b) }
package main import ( "encoding/json" "fmt" "reflect" ) type Student struct { Name string `json:"student_name"` Age int Score float32 Sex string } func (s Student) Print() { fmt.Println("---start----") fmt.Println(s) fmt.Println("---end----") } func (s Student) Set(name string, age int, score float32, sex string) { s.Name = name s.Age = age s.Score = score s.Sex = sex } func TestStruct(a interface{}) { tye := reflect.TypeOf(a) val := reflect.ValueOf(a) kd := val.Kind() if kd != reflect.Ptr && val.Elem().Kind() == reflect.Struct { fmt.Println("expect struct") return } num := val.Elem().NumField() val.Elem().Field(0).SetString("stu1000") for i := 0; i < num; i++ { fmt.Printf("%d %v\n", i, val.Elem().Field(i).Kind()) } fmt.Printf("struct has %d fields\n", num) tag := tye.Elem().Field(0).Tag.Get("json") fmt.Printf("tag=%s\n", tag) numOfMethod := val.Elem().NumMethod() fmt.Printf("struct has %d methods\n", numOfMethod) var params []reflect.Value val.Elem().Method(0).Call(params) } func main() { var a Student = Student{ Name: "stu01", Age: 18, Score: 92.8, } result, _ := json.Marshal(a) fmt.Println("json result:", string(result)) TestStruct(&a) fmt.Println(a) }