• 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)
    }
    反射案例二
  • 相关阅读:
    java io系列23之 BufferedReader(字符缓冲输入流)
    java io系列22之 FileReader和FileWriter
    java io系列21之 InputStreamReader和OutputStreamWriter
    java io系列20之 PipedReader和PipedWriter
    java io系列19之 CharArrayWriter(字符数组输出流)
    java io系列18之 CharArrayReader(字符数组输入流)
    java io系列17之 System.out.println("hello world")原理
    java io系列16之 PrintStream(打印输出流)详解
    java io系列15之 DataOutputStream(数据输出流)的认知、源码和示例
    java io系列14之 DataInputStream(数据输入流)的认知、源码和示例
  • 原文地址:https://www.cnblogs.com/zhangyafei/p/10693102.html
Copyright © 2020-2023  润新知