• 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
    ", p.Name)
    }
    
    func (p *BMW) DiDi() {
        fmt.Printf("%s is didi
    ", p.Name)
    }
    func (p *BMW) Hello() {
        fmt.Printf("%s is hello
    ", p.Name)
    }
    
    type BYD struct {
        Name string
    }
    
    func (p *BYD) GetName() string {
        return p.Name
    }
    
    func (p *BYD) Run() {
        fmt.Printf("%s is running
    ", p.Name)
    }
    
    func (p *BYD) DiDi() {
        fmt.Printf("%s is didi
    ", 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
    ", a)
    }
    接口实现案例Car

    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
    ", index, v)
    		case int, int32, int64:
    			fmt.Printf("%d params is int, value is %v
    ", index, v)
    		case float32, float64:
    			fmt.Printf("%d params is float, value is %v
    ", index, v)
    		case string:
    			fmt.Printf("%d params is string, value is %v
    ", index, v)
    		case Studnet:
    			fmt.Printf("%d params is student, value is %v
    ", index, v)
    		case *Studnet:
    			fmt.Printf("%d params is *student, value is %v
    ", index, v)
    		}
    	}
    }
    
    func main() {
    	var a interface{}
    	var b int
    	Test(b)
    	a = b
    	c := a.(int)
    	fmt.Printf("%d %T
    ", a, a)
    	fmt.Printf("%d %T
    ", 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
    ”, 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)
    }
    balance.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 (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)
    }
    instance.go
    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
    ", name)
        inst, err = balancer.DoBalance(insts)
        return
    }
    mgr.go
    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
    }
    random.go
    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
    }
    roundrobin.go
    • 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
    }
    hash.go
    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
    ")
                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
    main.go

    反射

    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
    ", stu, stu)
        }
    }
    
    func testInt(b interface{}) {
        val := reflect.ValueOf(b)
        val.Elem().SetInt(100)
    
        c := val.Elem().Int()
        fmt.Printf("get value interface{} %d
    ", c)
        fmt.Printf("string value: %d
    ", 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
    ", i, val.Elem().Field(i).Kind())
        }
    
        fmt.Printf("struct has %d fields
    ", num)
    
        tag := tye.Elem().Field(0).Tag.Get("json")
        fmt.Printf("tag=%s
    ", tag)
    
        numOfMethod := val.Elem().NumMethod()
        fmt.Printf("struct has %d methods
    ", 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)
    }
    反射案例二
  • 相关阅读:
    如何在WinPE下安装xp安装版
    好用、功能强大的JQuery弹出层插件
    设计模式-旧话重提之类工厂的使用
    How can I manage Internet Explorer Security Zones via the registry?
    设计模式行为模式Behavioral Patterns()之FlexibleService模式
    how to design a new tree view control
    在C#中通过webdav操作exchange
    Yahoo! User Interface Library (哈偶然发现了这个东西)
    设计模式[2]旧话重提之工厂模式
    const和static readonly 的区别
  • 原文地址:https://www.cnblogs.com/zhangyafei/p/10693102.html
Copyright © 2020-2023  润新知