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

2023-07-29,,

接口

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)
}

反射案例二

Go语言系列(六)- 接口和反射的相关教程结束。

《Go语言系列(六)- 接口和反射.doc》

下载本文的Word格式文档,以方便收藏与打印。