Go接口与反射

1、接口node

1.什么是interfacegolang

在面向对象编程中,能够这么说:“接口定义了对象的行为”, 那么具体的实现行为就取决于对象了。算法

在Go中,接口是一组方法签名。当一个类型为接口中的全部方法提供定义时,它被称为实现该接口。它与oop很是类似。接口指定类型应具备的方法,类型决定如何实现这些方法。编程

2.定义app

Interface类型能够定义一组方法,可是这些不须要实现,而且interface不能包含任何变量负载均衡

type 标识符 interface{
    Method1(参数列表) 返回值列表
    Method2(参数列表) 返回值列表
    ...
}

3.接口的实现dom

golang中的接口,不须要显式的实现,只要一个变量,含有接口类型中的全部方法,那么这个变量就实现这个接口。所以,golang中没有implement相似的关键字ide

若是一个变量含有多个interface类型的方法,那么这个变量就实现了多个接口
若是一个变量只含有一个interface的部分方法,那么这个变量没有实现这个函数

package main

import "fmt"

//定义一个薪资计算的接口,该接口有CalculateSalary方法,并无具体实现,只是一种规范
type SalaryCalculate interface{
    CalculateSalary() int
}

type Manager struct{
    basicpay int
    bonus int
}

type General struct{
    basicpay int
}

//类型去具体实现接口中的方法
func (this Manager) CalculateSalary() int{
    return this.basicpay + this.bonus
}

func (this General) CalculateSalary() int{
    return this.basicpay
}

func totalExpense(p []SalaryCalculate){
    total := 0
    for _, v := range p{
        //使用者不须要关心底层,只须要调用接口
        total += v.CalculateSalary()
    }
    fmt.Printf("总开支 %d", total)
}

func main(){
    Manager1 := Manager{10000, 6000}
    Manager2 := Manager{8000,7500}
    General1 := General{5000}
    //值类型实现接口
    employees := []SalaryCalculate{Manager1, Manager2, General1}
    totalExpense(employees)
}
接口实现

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

例如:咱们定义一个车的接口,该接口拥有各类车共同拥有的方法,而该接口能够表明各类车,咱们只须要让具体的车去实现这个接口。

例如:Linux中的一切皆文件的思想,不管是磁盘,内存,仍是...都是文件,咱们只须要定义一个操做文件的接口,而各个具体的东西去实现接口的方法,在调用的时候只须要经过接口进行操做

例如:GO中sort包下Sort方法为咱们提供了排序的原语,咱们只须要去实现接口的方法便可,该包具备很强的扩展性,不须要为每一个类型都定义一个方法,只须要提供一个排序的接口,而对于使用者也是友好的,咱们不须要去记住每一个类型所应该对应的排序方法。

type Interface interface {
    // Len is the number of elements in the collection.
    // Len 为集合内元素的总数
    Len() int
    // Less reports whether the element with
    // index i should sort before the element with index j.
    //
    // Less 返回索引为 i 的元素是否应排在索引为 j 的元素以前。
    Less(i, j int) bool
    // Swap swaps the elements with indexes i and j.
    // Swap 交换索引为 i 和 j 的元素
    Swap(i, j int)
}

package main

import (
    "sort"
    "fmt"
    "math/rand"
)

type Student struct{
    ID string
    Name string
}

type StudentArry []Student

func (this StudentArry) Len() int{
    return len(this)
}

func (this StudentArry) Less(i, j int) bool{
    return this[i].Name < this[j].Name
}

func (this StudentArry) Swap(i, j int){
    this[i], this[j] = this[j], this[i]
}

func trans(n StudentArry){
    for _, v := range n{
        fmt.Println(v)
    }
}

func main(){
    var stus StudentArry
    for i := 0; i < 10; i++{
        stu := Student{
            ID: fmt.Sprintf("154%d", rand.Int()),
            Name: fmt.Sprintf("stu%d", rand.Intn(100)),
        }
        stus = append(stus,stu)
    }
    trans(stus)
    fmt.Printf("\n")
    sort.Sort(stus)
    trans(stus)
}
经过排序接口实现排序

5.接口嵌套

package main

import "fmt"

type Read interface{
    Read()
}

type Write interface{
    Write()
}

type ReadWrite interface{
    Read
    Write
}

type File struct{

}

func (this File) Read(){
    fmt.Println("read data")
}

func (this File) Write(){
    fmt.Println("write data")
}

func Test(v ReadWrite)(){
    v.Read()
    v.Write()
}

func main(){
    var f File
    Test(f)
}
View Code

6.空接口,interface{}

空接口没有任何方法,因此全部类型都实现了空接口,也就是任何变量均可以赋值给空接口

var a int
var b interface{}
b = a

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

if sv, ok := v.(Stringer); ok{
    fmt.Println("ok")
}

7.类型断言,因为接口是通常类型,不知道具体类型,若是要转成具体类型,能够采用如下方法进行转换

var t int
var x inteface{}
x = t
y = x.(int) //转成int
package main

import "fmt"

type Student struct{
    Name string
}

func CheckType(items ...interface{}){
    for _, v := range items{
        switch v.(type) {
        case bool:
            fmt.Printf("%v params is bool\n", v)
        case int:
            fmt.Printf("%v params is int\n", v)
        case Student:
            fmt.Printf("%v params is Studen\nt", v)
        case *Student:
            fmt.Printf("%v params is *Student\n", v)
        }
    }
}

func main(){
    stu := Student{
        Name: "bob",
    }

    CheckType(false, 1, stu, &stu)
}
使用.(type)判断变量的类型

实现一个通用的链表类

//link.go
package main

import "fmt"

type Node struct{
    Data interface{}
    Next *Node
}

type Link struct{
    Head *Node
    Tail *Node
}

func (this *Link) IsEmpty() bool{
    return this.Head == nil
}

func (this *Link) Init(node *Node){
    this.Head = node
    this.Tail = node
}

func (this *Link) Insert(data interface{}){
    node := &Node{
        Data: data,
    }

    if this.IsEmpty(){
        this.Init(node)
        return
    }
    node.Next = this.Head
    this.Head = node
}

func (this *Link) Trans(){
    cur := this.Head
    for cur != nil{
        fmt.Println(cur.Data)
        cur = cur.Next
    }
}

func (this *Link) Append(data interface{}){
    node := &Node{
        Data: data,
    }

    if this.IsEmpty(){
        this.Init(node)
        return
    }

    this.Tail.Next = node
    this.Tail = node
}


//main.go
package main

import "fmt"

func main(){
    var link Link
    for i := 0; i < 10; i++{
        link.Insert(fmt.Sprintf("stu%d",i))
    }
    for i := 0; i < 10; i++{
        link.Append(fmt.Sprintf("stu%d",i))
    }
    link.Trans()
}
View Code

变量slice和接口slice之间的赋值操做,for range

2、反射

能够在运行时动态获取变量的相关信息

1.两个函数

reflect.TypeOf,获取变量的类型,返回reflect.Type类型
reflect.ValueOf,获取变量的值,返回reflect.Value类型
import (
    "fmt"
    "reflect"
)
type Student struct{
    Name string
    Age int
    Score float32
}

func Test(n interface{}){
    a := reflect.TypeOf(n)
    fmt.Println(a)
    v := reflect.ValueOf(n)
    fmt.Println(v)
    fmt.Printf("a type is %T; v type is %T",a, v)
}


func main(){
    var stu Student
    Test(stu)
}

/*
main.Student
{ 0 0}
a type is *reflect.rtype; v type is reflect.Value
*/
View Code

经过reflect.Value类型咱们能够分析变量的各类属性

其中,reflect.Value.Kind,获取变量的类别,返回一个常量

const (
    Invalid Kind = iota
    Bool
    Int
    Int8
    Int16
    Int32
    Int64
    Uint
    Uint8
    Uint16
    Uint32
    Uint64
    Uintptr
    Float32
    Float64
    Complex64
    Complex128
    Array
    Chan
    Func
    Interface
    Map
    Ptr
    Slice
    String
    Struct
    UnsafePointer
)
type Student struct{
    Name string
    Age int
    Score float32
}

func Test(n interface{}){
    a := reflect.TypeOf(n)
    fmt.Println(a)
    v := reflect.ValueOf(n)
    k := v.Kind()
    fmt.Println(k)
}


func main(){
    var stu Student
    Test(stu)
}

/*
main.Student
struct
能够看出stu这个变量的类型是main包下的Student
而其类别是结构体
*/
类型和类别

固然咱们也能够将reflect.Value类型逆转成interface{}类型

reflect.Value.Interface() //转换成interface{}类型

其转换关系为

变量 <------> interface{} <------> reflect.Value

获取变量的值

reflect.ValueOf(x).Float()
reflect.ValueOf(x).Int()
reflect.ValueOf(x).String()
reflect.ValueOf(x).Bool()

经过反射来改变变量的值

type Student struct{
    Name string
    Age int
    Score float32
}

func Test(n interface{}){
    v := reflect.ValueOf(n)
    //注意v是指针类型,因此须要经过Elem()转换,其本质和*v同样
    v.Elem().SetInt(99)    
}


func main(){
    b := 100
    //注意得传指针类型,若是传值类型会panic
    Test(&b)
    fmt.Println(b)
}
View Code

用反射操做结构体

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

package main

import (
    "fmt"
    "reflect"
)

type Student struct{
    Name string
    Age int
    Score float32
}

func (this Student) Print(){
    fmt.Println(this)
}


func Test(p interface{}){
    val := reflect.ValueOf(p)
    if val.Kind() != reflect.Struct{
        fmt.Println("expect struct")
        return
    }
    fieldNum := val.NumField()
    methodNum := val.NumMethod()
    fmt.Println(fieldNum, methodNum)
    //调用第几个方法
    val.Method(0).Call(nil)
}


func main(){
    stu := Student{
        Name: "stu100",
        Age: 18,
        Score: 99.5,
    }

    Test(stu)
}
View Code

接口实例

实现一个负载均衡调度算法,支持随机、轮训等,思考如何实现如内置sort.Sort()同样,支持第三方扩展的需求

//balance.go
/*
定义一个负载均衡算法接口,该接口接收一个包含主机实例的切片,经过算法返回一个主机实例
*/
package balance

type Balancer interface{
    DoBalance([] *Instance) (*Instance, error)
}


//instance.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 (this *Instance) GetHost() string{
    return this.host
}

func (this *Instance) GetPort() int{
    return this.port
}

func (this *Instance) String() string{
    return this.host + ":" + strconv.Itoa(this.port)
}


//random.go
/*
咱们写一个包内置的随机算法,经过init函数进行初始化注册,该算法实现了负载均衡算法接口
*/
package balance

import (
    "errors"
    "math/rand"
)

type RandomBalance struct{

}

func init(){
    RegisterBalance("random", &RandomBalance{})
}

func (this *RandomBalance)  DoBalance(insts [] *Instance) (inst *Instance,err error){
    lens := len(insts)

    if lens == 0{
        err = errors.New("no instance")
        return
    }
    index := rand.Intn(lens)
    inst = insts[index]
    return
}


//mgr.go
/*
一个注册中心,拥有注册过的算法(不管是咱们内置的仍是用户扩展的),
*/
package balance

import "fmt"

type BalanceMgr struct{
    allBalancer map[string]Balancer
}

var mgr = BalanceMgr{
    allBalancer: make(map[string]Balancer),
}

func (this *BalanceMgr) registerBalance(name string,b Balancer){
      this.allBalancer[name] = b
}

func RegisterBalance(name string,b Balancer){
    mgr.registerBalance(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 banlancer", name)
        return
    }
    inst, err = balancer.DoBalance(insts)
    return
}
balance包
//poll.go
/*
看成用户扩展的算法,实现负载均衡算法接口,并在注册中心注册
*/
package main

import (
    "go_dev/day06/t9/balance"
    "errors"
)

type PollBalance struct{
    ctn int
}

func init(){
    balance.RegisterBalance("poll", &PollBalance{})
}


func (this *PollBalance) DoBalance(insts [] *balance.Instance) (inst *balance.Instance,err error) {
    lens := len(insts)
    if lens == 0{
        err = errors.New("No instance")
        return
    }
    this.ctn = (this.ctn + 1) % lens
    inst = insts[this.ctn]
    return
}


//main.go
package main

import (
    "time"
    "fmt"
    "math/rand"
    "go_dev/day06/t9/balance"
    "os"
)

func main()  {
    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]
    }

    for {
        inst, err := balance.DoBalance(balanceName, insts)
        if err != nil{
            fmt.Println(err)
            continue
        }
        fmt.Println(inst)
        time.Sleep(time.Second)
    }
   }
main包
相关文章
相关标签/搜索