Go语言系列(六)- 接口和反射

释放双眼,带上耳机,听听看~!

接口

1. 定义: Interface类型可以定义一组方法,但是这些不需要实现。并且interface不能包含任何变量。

1
2
3
4
5
1type example interface{
2        Method1(参数列表) 返回值列表
3        Method2(参数列表) 返回值列表
4}
5

2.interface类型默认是一个指针

1
2
3
4
5
6
7
8
9
10
1type example interface{
2
3           Method1(参数列表) 返回值列表
4           Method2(参数列表) 返回值列表
5           …
6   }
7
8   var a example
9   a.Method1()
10

3. 接口实现

  • a. Golang中的接口,不需要显示的实现。只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。因此,golang中没有implement类似的关键字
  • b. 如果一个变量含有了多个interface类型的方法,那么这个变量就实现了多个接口。
  • c. 如果一个变量只含有了1个interface的方部分方法,那么这个变量没有实现这个接口。

Go语言系列(六)- 接口和反射Go语言系列(六)- 接口和反射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
1package main
2
3import "fmt"
4
5type Car interface {
6    GetName() string
7    Run()
8    DiDi()
9}
10
11type Test interface {
12    Hello()
13}
14
15type BMW struct {
16    Name string
17}
18
19func (p *BMW) GetName() string {
20    return p.Name
21}
22
23func (p *BMW) Run() {
24    fmt.Printf("%s is running\n", p.Name)
25}
26
27func (p *BMW) DiDi() {
28    fmt.Printf("%s is didi\n", p.Name)
29}
30func (p *BMW) Hello() {
31    fmt.Printf("%s is hello\n", p.Name)
32}
33
34type BYD struct {
35    Name string
36}
37
38func (p *BYD) GetName() string {
39    return p.Name
40}
41
42func (p *BYD) Run() {
43    fmt.Printf("%s is running\n", p.Name)
44}
45
46func (p *BYD) DiDi() {
47    fmt.Printf("%s is didi\n", p.Name)
48}
49
50func main() {
51    var car Car
52    var test Test
53    fmt.Println(car)
54
55    // var bwm = BMW{}
56    // bwm.Name = "宝马"
57    bwm := &BMW{
58        Name: "宝马",
59    }
60    car = bwm
61    car.Run()
62
63    test = bwm
64    test.Hello()
65
66    byd := &BMW{
67        Name: "比亚迪",
68    }
69    car = byd
70    car.Run()
71    // var a interface{}
72    // var b int
73    // var c float32
74
75    // a = b
76    // a = c
77    // fmt.Printf("type of a %T\n", a)
78}
79

接口实现案例Car

4.多态:一种事物的多种形态,都可以按照统一的接口进行操作

sort排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
1package main
2
3import (
4   "fmt"
5   "math/rand"
6   "sort"
7)
8
9type Student struct {
10  Name string
11  Id   string
12  Age  int
13}
14
15type Book struct {
16  Name   string
17  Author string
18}
19
20type StudentArray []Student
21
22func (self StudentArray) Len() int {
23  return len(self)
24}
25
26func (self StudentArray) Less(i, j int) bool {
27  return self[i].Name > self[j].Name
28}
29
30func (self StudentArray) Swap(i, j int) {
31  self[i], self[j] = self[j], self[i]
32}
33
34func main() {
35  var stus StudentArray
36
37  for i := 0; i < 10; i++ {
38      stu := Student{
39          Name: fmt.Sprintf("stu%d", rand.Intn(100)),
40          Id:   fmt.Sprintf("110%d", rand.Int()),
41          Age:  rand.Intn(100),
42      }
43      stus = append(stus, stu)
44  }
45
46  for _, v := range stus {
47      fmt.Println(v)
48  }
49
50  fmt.Println()
51
52  sort.Sort(stus)
53
54  for _, v := range stus {
55      fmt.Println(v)
56  }
57}
58

5. 接口嵌套:一个接口可以嵌套在另外的接口,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1type ReadWrite interface {
2   Read(b Buffer) bool
3   Write(b Buffer) bool
4}
5type Lock interface {
6   Lock()
7   Unlock()
8}
9type File interface {
10   ReadWrite
11   Lock
12   Close()
13}
14

Go语言系列(六)- 接口和反射Go语言系列(六)- 接口和反射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
1package main
2
3import "fmt"
4
5type Reader interface {
6    Read()
7}
8
9type Writer interface {
10    Write()
11}
12
13type ReadWriter interface {
14    Reader
15    Writer
16}
17
18type File struct {
19}
20
21func (self *File) Read() {
22    fmt.Println("read data")
23}
24
25func (self *File) Write() {
26    fmt.Println("write data")
27}
28
29func Test(rw ReadWriter) {
30    rw.Read()
31    rw.Write()
32}
33
34func main() {
35    var f *File
36    var b interface{}
37    b = f
38    // Test(f)
39
40    v, ok := b.(ReadWriter)
41    fmt.Println(v, ok)
42}
43

接口嵌套文件读写案例

6. 类型断言,由于接口是一般类型,不知道具体类型,如果要转成具体类型,可以采用以下方法进行转换:

1
2
3
4
5
1var t int
2   var x interface{}
3   x = t
4   y, ok = x.(int)   //转成int,带检查
5

7. 练习,写一个函数判断传入参数的类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
1package main
2
3import (
4   "fmt"
5)
6
7type Studnet struct {
8   Name string
9   Sex  string
10}
11
12func Test(a interface{}) {
13  // b, ok := a.(int)
14  b, ok := a.(Studnet)
15  if ok == false {
16      fmt.Println("convert failed")
17      return
18  }
19  // b += 3
20  fmt.Println(b)
21}
22
23func just(items ...interface{}) {
24  for index, v := range items {
25      switch v.(type) {
26      case bool:
27          fmt.Printf("%d params is bool, value is %v\n", index, v)
28      case int, int32, int64:
29          fmt.Printf("%d params is int, value is %v\n", index, v)
30      case float32, float64:
31          fmt.Printf("%d params is float, value is %v\n", index, v)
32      case string:
33          fmt.Printf("%d params is string, value is %v\n", index, v)
34      case Studnet:
35          fmt.Printf("%d params is student, value is %v\n", index, v)
36      case *Studnet:
37          fmt.Printf("%d params is *student, value is %v\n", index, v)
38      }
39  }
40}
41
42func main() {
43  var a interface{}
44  var b int
45  Test(b)
46  a = b
47  c := a.(int)
48  fmt.Printf("%d %T\n", a, a)
49  fmt.Printf("%d %T\n", c, c)
50
51  var d Studnet = Studnet{
52      Name: "stu1",
53      Sex:  "female",
54  }
55  Test(d)
56  just(28, 8.2, "this is a test", d, &d)
57}
58

8. 类型断言,采用type switch方式

9. 空接口.interface{}

空接口没有任何方法,所以所有类型都实现了空接口。

1
2
3
4
1var a int
2   var b interface{}
3   b  = a
4

10.判断一个变量是否实现了指定接口

1
2
3
4
5
6
7
8
1type Stringer interface {
2           String() string
3   }
4   var v MyStruct
5   if sv, ok := v.(Stringer); ok {
6          fmt.Printf(“v implements String(): %s\n”, sv.String());
7   }
8

11. 实现一个通用的链表类

link.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
1package main
2
3import (
4   "fmt"
5)
6
7type LinkNode struct {
8   data interface{}
9   next *LinkNode
10}
11
12type Link struct {
13  head *LinkNode
14  tail *LinkNode
15}
16
17func (p *Link) InsertHead(data interface{}) {
18  node := &LinkNode{
19      data: data,
20      next: nil,
21  }
22
23  if p.tail == nil && p.head == nil {
24      p.tail = node
25      p.head = node
26      return
27  }
28
29  node.next = p.head
30  p.head = node
31}
32func (p *Link) InsertTail(data interface{}) {
33  node := &LinkNode{
34      data: data,
35      next: nil,
36  }
37
38  if p.tail == nil && p.head == nil {
39      p.tail = node
40      p.head = node
41      return
42  }
43
44  p.tail.next = node
45  p.tail = node
46}
47
48func (p *Link) Trans() {
49  q := p.head
50  for q != nil {
51      fmt.Println(q.data)
52      q = q.next
53  }
54}
55

main.go

1
2
3
4
5
6
7
8
9
10
11
1package main
2
3func main() {
4   var initLink Link
5   for i := 0; i < 10; i++ {
6       // initLink.InsertHead(i)
7       initLink.InsertTail(i)
8   }
9   initLink.Trans()
10}
11

12. interface{},接口中一个方法也没有,所以任何类型都实现了空接口,也就是任何变量都可以赋值给空接口。

1
2
3
4
1var a int
2   var b interface{}
3   b = a
4

13.  变量slice和接口slice之间赋值操作,for range  

1
2
3
4
1var a []int
2   var b []interface{}
3   b = a
4

 

14. 实现一个负载均衡调度算法,支持随机、轮训等算法

  • balance

Go语言系列(六)- 接口和反射Go语言系列(六)- 接口和反射

1
2
3
4
5
6
1package balance
2
3type Balancer interface {
4    DoBalance([]*Instance, ...string) (*Instance, error)
5}
6

balance.go

Go语言系列(六)- 接口和反射Go语言系列(六)- 接口和反射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1package balance
2
3import "strconv"
4
5type Instance struct {
6    host string
7    port int
8}
9
10func NewInstance(host string, port int) *Instance {
11    return &Instance{
12        host: host,
13        port: port,
14    }
15}
16
17func (p *Instance) GetHost() string {
18    return p.host
19}
20
21func (p *Instance) GetPort() int {
22    return p.port
23}
24
25func (p *Instance) String() string {
26    return p.host + ":" + strconv.Itoa(p.port)
27}
28

instance.go

Go语言系列(六)- 接口和反射Go语言系列(六)- 接口和反射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1package balance
2
3import "fmt"
4
5type BalanceMgr struct {
6    allBalancer map[string]Balancer
7}
8
9var mgr = BalanceMgr{
10    allBalancer: make(map[string]Balancer),
11}
12
13func (p *BalanceMgr) RegisterBalancer(name string, b Balancer) {
14    p.allBalancer[name] = b
15}
16
17func RegisterBalancer(name string, b Balancer) {
18    mgr.RegisterBalancer(name, b)
19}
20
21func DoBalance(name string, insts []*Instance) (inst *Instance, err error) {
22    balancer, ok := mgr.allBalancer[name]
23    if !ok {
24        err = fmt.Errorf("Not found %s balancer", name)
25        return
26    }
27    fmt.Printf("use %s balance\n", name)
28    inst, err = balancer.DoBalance(insts)
29    return
30}
31

mgr.go

Go语言系列(六)- 接口和反射Go语言系列(六)- 接口和反射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1package balance
2
3import (
4    "errors"
5    "math/rand"
6)
7
8func init() {
9    RegisterBalancer("random", &RandomBalance{})
10}
11
12type RandomBalance struct {
13}
14
15func (p *RandomBalance) DoBalance(insts []*Instance, key ...string) (inst *Instance, err error) {
16    if len(insts) == 0 {
17        err = errors.New("No instance")
18        return
19    }
20    lens := len(insts)
21    index := rand.Intn(lens)
22    inst = insts[index]
23    return
24}
25

random.go

Go语言系列(六)- 接口和反射Go语言系列(六)- 接口和反射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1package balance
2
3import (
4    "errors"
5)
6
7func init() {
8    RegisterBalancer("roundrobin", &RoundRobinBalance{})
9}
10
11type RoundRobinBalance struct {
12    curIndex int
13}
14
15func (p *RoundRobinBalance) DoBalance(insts []*Instance, key ...string) (inst *Instance, err error) {
16    if len(insts) == 0 {
17        err = errors.New("No instance")
18        return
19    }
20    lens := len(insts)
21    if p.curIndex >= lens {
22        p.curIndex = 0
23    }
24    inst = insts[p.curIndex]
25    p.curIndex = (p.curIndex + 1) % lens
26    return
27}
28

roundrobin.go

  • main

Go语言系列(六)- 接口和反射Go语言系列(六)- 接口和反射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
1package main
2
3import (
4    "fmt"
5    "go_dev/day7/example/example1/balance"
6    "hash/crc32"
7    "math/rand"
8)
9
10type HashBalance struct {
11}
12
13func init() {
14    balance.RegisterBalancer("hash", &HashBalance{})
15}
16
17func (p *HashBalance) DoBalance(insts []*balance.Instance, key ...string) (inst *balance.Instance, err error) {
18    var defkey string = fmt.Sprintf("%d", rand.Int())
19    if len(key) > 0 {
20        // err := fmt.Errorf("hash balance must pass the hash key")
21        defkey = key[0]
22    }
23    lens := len(insts)
24    if lens == 0 {
25        err = fmt.Errorf("No backend instance")
26        return
27    }
28    crcTable := crc32.MakeTable(crc32.IEEE)
29    hashVal := crc32.Checksum([]byte(defkey), crcTable)
30    index := int(hashVal) % lens
31    inst = insts[index]
32
33    return
34}
35

hash.go

Go语言系列(六)- 接口和反射Go语言系列(六)- 接口和反射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
1package main
2
3import (
4    "fmt"
5    "go_dev/day7/example/example1/balance"
6    "math/rand"
7    "os"
8    "time"
9)
10
11func main() {
12    // 定义一个空切片
13    // insts := main([]*balance.Instance)
14    var insts []*balance.Instance
15    for i := 0; i < 16; i++ {
16        host := fmt.Sprintf("192.168.%d.%d", rand.Intn(255), rand.Intn(255))
17        one := balance.NewInstance(host, 8080)
18        insts = append(insts, one) // 自动对空切片进行扩容
19    }
20    // 选择负载均衡算法
21    var balanceName = "random"
22    if len(os.Args) > 1 {
23        balanceName = os.Args[1]
24    }
25    // var balancer balance.Balancer
26    // var conf = "random"
27    // if len(os.Args) > 1 {
28    //     conf = os.Args[1]
29    // }
30    // if conf == "random" {
31    //     balancer = &balance.RandomBalance{} // 随机
32    //     fmt.Println("use random balancer")
33    // } else if conf == "roundrobin" {
34    //     balancer = &balance.RoundRobinBalance{} // 轮询
35    //     fmt.Println("use roundrobin balancer")
36    // }
37    // balancer := &balance.RandomBalance{}  // 随机
38    // balancer := &balance.RoundRobinBalance{} // 轮询
39
40    for {
41        inst, err := balance.DoBalance(balanceName, insts)
42        if err != nil {
43            // fmt.Println("do balance err:", err)
44            fmt.Fprintf(os.Stdout, "do balance error\n")
45            continue
46        }
47        fmt.Println(inst)
48        time.Sleep(time.Second)
49    }
50
51}
52
53// 运行
54// go run go_dev/day7/example/example1/main random
55// go run go_dev/day7/example/example1/main roundrobin
56// go run go_dev/day7/example/example1/main hash
57// 编译
58// go build go_dev/day7/example/example1/main
59

main.go

反射

1. 反射:可以在运行时动态获取变量的相关信息

1
2
1Import (“reflect”)
2

两个函数:

  • a. reflect.TypeOf,获取变量的类型,返回reflect.Type类型
  • b. reflect.ValueOf,获取变量的值,返回reflect.Value类型
  • c. reflect.Value.Kind,获取变量的类别,返回一个常量
  • d. reflect.Value.Interface(),转换成interface{}类型

2. reflect.Value.Kind()方法返回的常量

3. 获取变量的值:

1
2
3
4
5
1reflect.ValueOf(x).Float()
2reflect.ValueOf(x).Int()
3reflect.ValueOf(x).String()
4reflect.ValueOf(x).Bool()
5

4. 通过反射的来改变变量的值

1
2
3
4
5
1reflect.Value.SetXX相关方法,比如:
2reflect.Value.SetFloat(),设置浮点数
3reflect.Value.SetInt(),设置整数
4reflect.Value.SetString(),设置字符串
5

5. 用反射操作结构体

1
2
3
1a. reflect.Value.NumField()获取结构体中字段的个数
2b. reflect.Value.Method(n).Call来调用结构体中的方法
3

6.案例

Go语言系列(六)- 接口和反射Go语言系列(六)- 接口和反射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
1package main
2
3import (
4    "fmt"
5    "reflect"
6)
7
8type Student struct {
9    Name  string
10    Age   int
11    Score float32
12}
13
14func test(b interface{}) {
15    t := reflect.TypeOf(b)
16    fmt.Println(t)
17    v := reflect.ValueOf(b)
18    k := v.Kind()
19    fmt.Println(k)
20
21    iv := v.Interface()
22    stu, ok := iv.(Student)
23    if ok {
24        fmt.Printf("%v %T\n", stu, stu)
25    }
26}
27
28func testInt(b interface{}) {
29    val := reflect.ValueOf(b)
30    val.Elem().SetInt(100)
31
32    c := val.Elem().Int()
33    fmt.Printf("get value interface{} %d\n", c)
34    fmt.Printf("string value: %d\n", val.Elem().Int())
35}
36
37func main() {
38    var a Student = Student{
39        Name:  "stu1",
40        Age:   18,
41        Score: 92,
42    }
43    test(a)
44    var b int = 1
45    testInt(&b)
46    fmt.Println(b)
47}
48

反射案例一

Go语言系列(六)- 接口和反射Go语言系列(六)- 接口和反射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
1package main
2
3import (
4    "encoding/json"
5    "fmt"
6    "reflect"
7)
8
9type Student struct {
10    Name  string `json:"student_name"`
11    Age   int
12    Score float32
13    Sex   string
14}
15
16func (s Student) Print() {
17    fmt.Println("---start----")
18    fmt.Println(s)
19    fmt.Println("---end----")
20}
21
22func (s Student) Set(name string, age int, score float32, sex string) {
23
24    s.Name = name
25    s.Age = age
26    s.Score = score
27    s.Sex = sex
28}
29
30func TestStruct(a interface{}) {
31    tye := reflect.TypeOf(a)
32    val := reflect.ValueOf(a)
33    kd := val.Kind()
34    if kd != reflect.Ptr && val.Elem().Kind() == reflect.Struct {
35        fmt.Println("expect struct")
36        return
37    }
38
39    num := val.Elem().NumField()
40    val.Elem().Field(0).SetString("stu1000")
41    for i := 0; i < num; i++ {
42        fmt.Printf("%d %v\n", i, val.Elem().Field(i).Kind())
43    }
44
45    fmt.Printf("struct has %d fields\n", num)
46
47    tag := tye.Elem().Field(0).Tag.Get("json")
48    fmt.Printf("tag=%s\n", tag)
49
50    numOfMethod := val.Elem().NumMethod()
51    fmt.Printf("struct has %d methods\n", numOfMethod)
52    var params []reflect.Value
53    val.Elem().Method(0).Call(params)
54}
55
56func main() {
57    var a Student = Student{
58        Name:  "stu01",
59        Age:   18,
60        Score: 92.8,
61    }
62
63    result, _ := json.Marshal(a)
64    fmt.Println("json result:", string(result))
65
66    TestStruct(&a)
67    fmt.Println(a)
68}
69

反射案例二

 

给TA打赏
共{{data.count}}人
人已打赏
安全技术

c++ list, vector, map, set 区别与用法比较

2022-1-11 12:36:11

病毒疫情

省级远程会诊平台 助攻我省战“疫”

2020-2-18 10:02:00

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索