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)
}
接口实现案例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\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)
}
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\n", 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\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
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\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)
}
反射案例二

 

posted @ 2019-04-11 22:29  DreamBoy_张亚飞  阅读(339)  评论(0编辑  收藏  举报