zoukankan      html  css  js  c++  java
  • 接口、反射

    接口

    1、定义

      Interface类型可以定义一组方法,用来表示一个对象的行为特征。

      interface不能包含任何变量。

    type Animal interface{
        Talk(参数列列表) 返回值列列表
        Eat(参数列列表) 返回值列列表
    … }

    2、 interface类型是引用类型

    3、接口实现 

      a. Golang中的接口,不需要显示的实现。只要 一个对象,实现了接口类型中的所有方法,那么这个对象就实现这个接口。

      b. 如果一个对象实现了多个interface类型的方法,那么这个对象就实现了多个接口。 

    package main
    
    
    import (
        "fmt"
    )
    
    type Animal interface {
        Eat() 
        Talk()
    }
    
    type Dog struct {    
    }
    
    func (d *Dog) Eat() {
        fmt.Println("dog is eating")
    }
    
    func (d *Dog) Talk() {
        fmt.Println("dog is wawa!")
    }
    
    type Cat struct {    
    }
    
    func (d *Cat) Eat() {
        fmt.Println("cat is eating")
    }
    
    func (d *Cat) Talk() {
        fmt.Println("cat is miaomiao!")
    }
    
    func main() {
        var a Animal
        //a.Eat()  //报错,接口是引用类型
        var d Dog
        d.Eat()
    
        a = &d
        a.Eat()
    
        var c Cat
        a = &c
        a.Eat()
    }
    View Code

     4、多态 

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

    package main
    
    
    import (
        "fmt"
    )
    
    type Animal interface {
        Eat() 
        Talk()
    }
    
    type Dog struct {
        Name string
    }
    
    func (d *Dog) Eat() {
        fmt.Println(d.Name, "is eating")
    }
    
    func (d *Dog) Talk() {
        fmt.Println(d.Name, " is wawa!")
    }
    
    type Cat struct {
        Name string
    }
    
    func (d *Cat) Eat() {
        fmt.Println(d.Name, "is eating")
    }
    
    func (d *Cat) Talk() {
        fmt.Println(d.Name, "is 喵喵!")
    }
    
    func main() {
        var animalList []Animal  //定义一个接口类型的切片
        d := &Dog{
            Name: "小黄",
        }
        animalList = append(animalList, d)
    
        d1 := &Dog{
            Name: "旺财",
        }
        animalList = append(animalList, d1)
    
        c1 := &Cat{
            Name: "小白",
        }
        animalList = append(animalList, c1)
    
        for _, v := range animalList {
            v.Eat()
            v.Talk()
        }
    }
    View Code

     5、空接口,Interface{}

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

    package main
    
    import (
        "fmt"
    )
    
    func main(){
        var a interface{}  //可以存所有的数据类型,一般不用,尽量使用强类型的数据类型,代码便于维护
        var b int = 1000
    
        a = b
        fmt.Println(a)
    
        var c string = "hello"
        a = c
        fmt.Println(a)
    }

    6、接口嵌套  

      一个接口可以嵌套在另外的接口(实例必须实现所有接口内的方法)

    package main
    
    import (
        "fmt"
    )
    
    type Eater interface {
        Eat()
    }
    
    type Talker interface {
        Talk()
    }
    
    type Animal interface {
        Eater
        Talker
    }
    
    func main() {
        d := &Dog{}
        var a Animal
        a = d
        a.Eat()
    }
    View Code

    7、类型断言。如果我们反向要知道这个接口变量里面实际存储的是哪个类型的对象可以采用以下方法进行转换:

    var t int
    var x interface{}
    x = t
    y = x.(int)//转成int
    
    
    var t int
    var x interface{}
    x = t
    y, ok = x.(int)
    //转成int,带检查
    package main
    
    import (
        "fmt"
    )
    
    type Eater interface {
        Eat()
    }
    
    type Talker interface {
        Talk()
    }
    
    type Animal interface {
        Eater
        Talker
    }
    
    type Dog struct {
    }
    
    func (d *Dog) Eat() {
        fmt.Println("eating")
    }
    
    func (d *Dog) Talk() {
        fmt.Println("eating")
    }
    
    type Cat struct {
    }
    
    func (c *Cat) Eat() {
        fmt.Println("eating")
    }
    
    func (c *Cat) Talk() {
        fmt.Println("eating")
    }
    
    func justify(a Animal) {
        dog, ok := a.(*Dog)  //类型断言,判断类型里面存的是Dog,还是Cat
        if !ok {
            fmt.Println("conver to dog failed")
            return
        }
        dog.Eat()
    }
    
    func main() {
        d := &Dog{}
        var a Animal
        a = d
        a.Eat()
    
        justify(a)
        
        a = &Cat{}
        justify(a)
    }
    类型断言

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

    package main
    
    import (
        "fmt"
    )
    
    func justify(items ...interface{}) {
        for index, v := range items {
            switch v.(type) {//类型断言
            case int:
                fmt.Printf("第 %d 个参数 is int
    ", index)
            case int32:
                fmt.Printf("第 %d 个参数 is int32
    ", index)
            case float32:
                fmt.Printf("第 %d 个参数 is float32
    ", index)
            
            }
        }
    }
    
    func main(){
        var a int
        var b float32
        var c int32
        justify(a, b, c)
    
        
    }
    package main
    
    import (
        "fmt"
    )
    
    type Eater interface {
        Eat()
    }
    
    type Talker interface {
        Talk()
    }
    
    type Animal interface {
        Eater
        Talker
    }
    
    type Dog struct {
    }
    
    func (d *Dog) Eat() {
        fmt.Println("eating")
    }
    
    func (d *Dog) Talk() {
        fmt.Println("eating")
    }
    
    type Cat struct {
    }
    
    func (c *Cat) Eat() {
        fmt.Println("eating")
    }
    
    func (c *Cat) Talk() {
        fmt.Println("eating")
    }
    
    func justify(a Animal) {
        switch t := a.(type) {
        case *Dog:
            t.Eat()
            fmt.Printf("t is dog
    ")
        case *Cat:
            t.Eat()
            fmt.Printf("t is cat
    ")
        }
    }
    
    func main() {
        d := &Dog{}
        var a Animal
        a = d
        a.Eat()
    
        justify(a)
        a = &Cat{}
    
        justify(a)
    }
    type switch方式类型断言

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

    type Stringer interface {
        String() string
    }
    v := &MyStruct{}
    var tmp interface{} = v 
    if sv, ok :=tmp.(Stringer); ok {
        fmt.Printf(“v implements String(): %s
    ”, sv.String());
    }

    课后练习:

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

    package main
    
    import (
        "fmt"
        "math/rand"
    )
    
    func doBalance(balance Balance, addrList []string) (addr string) {
        return balance.DoBalance(addrList)
    }
    
    func main() {
        var addrList []string
        for i := 0; i < 5; i++ {
            addr := fmt.Sprintf("%d.%d.%d.%d:8080", rand.Intn(255), rand.Intn(255), rand.Intn(255), rand.Intn(255))
            //根据于格式说明符进行格式化并返回其结果字符串。
            addrList = append(addrList, addr)
        }
    
        var balanceName string
    
        fmt.Scanf("%s", &balanceName) //从控制台读取
    
        var balance Balance
        if balanceName == "random" {
            balance = &RandBalance{}
        } else if balanceName == "roundrobin" {
            balance = &RoundBalance{}
        } else {
            balance = &RandBalance{}
        }
    
        for i := 0; i < 10; i++ {
            addr := doBalance(balance, addrList)
            fmt.Println(addr)
        }
    
    }
    main

    接口:

    package main
    
    
    type Balance interface {
         DoBalance([]string) string
    }
    balance

    随机算法:

    package main
    
    import (
        "math/rand"
    )
    
    type RandBalance struct {
    
    }
    
    func (r *RandBalance) DoBalance(addrList []string) string {
         l := len(addrList)
         index := rand.Intn(l)
         return addrList[index]
    }
    random

    轮询算法:

    package main
    
    type RoundBalance struct {
        curIndex int
    }
    
    func (r *RoundBalance) DoBalance(addrList []string) string {
        l := len(addrList)
        r.curIndex = r.curIndex % l
        addr := addrList[r.curIndex]
        r.curIndex++
        return addr
    }
    round

    手机支付接口的实现:

    package main
    
     import(
         "fmt"
     )
    
     func main(){
         phone := &Phone{
             PayMap:make(map[string]Pay, 16),
         }
         //phone.OpenWeChatPay()   //开通微信支付
         //phone.OpenAliPay()       //开通阿里支付
         weChat := &WeChatPay{}
         var tmp interface{} = weChat    
         _, ok := tmp.(Pay)  //tmp这个变量是否实现了Pay这个接口
         if ok {
             fmt.Println("weChat is implement Pay interface")         
         }
         phone.OpenPay("ali_pay", &AliPay{})   //开通阿里支付
    
         err := phone.PayMoney("wechat_pay", 20.32)
         if err != nil {
             fmt.Printf("支付失败,失败原因:%v
    ", err)
             fmt.Printf("使用支付宝支付
    ")
             err = phone.PayMoney("ali_pay", 20.32)
             if err != nil {
                fmt.Printf("支付失败,失败原因:%v
    ", err)
                return
             }
         }
    
         fmt.Println("支付成功,欢迎再次光临!")
     }
    main

    支付接口:

    package main
    
    
    type Pay interface {
        pay(user_id int64, money float32) error
    }
    pay

    alipay支付:

    package main
    
    
    import (
        "fmt"
    )
    
    type AliPay struct {
    
    }
    
    
    func (a *AliPay) pay(user_id int64, money float32) error {
        fmt.Println("1. 连接到阿里的服务器")
        fmt.Println("2. 找到对应的用户")
        fmt.Println("3. 扣钱")
        fmt.Println("4. 返回支付是否成功")
    
        fmt.Println("5. 连接到阿里的服务器")
        fmt.Println("6. 找到对应的用户")
        fmt.Println("7. 扣钱")
        fmt.Println("8. 返回支付是否成功")
        return nil
    }
    View Code

    weixin支付:

    package main
    
    import (
        "fmt"
    )
    
    type WeChatPay struct {
    
    }
    
    
    func (w *WeChatPay) pay(user_id int64, money float32) error {
        fmt.Println("1. 连接到微信支付的服务器")
        fmt.Println("2. 找到对应的用户")
        fmt.Println("3. 检查余额是否充足")
        fmt.Println("4. 扣钱")
        fmt.Println("5. 返回支付是否成功")
    
        return nil
    }
    View Code

    具体支付实现:

    package main
    
    import (
        "fmt"
    )
    
    type Phone struct {
        PayMap map[string]Pay   //Pay为接口
    }
    
    func (p *Phone) OpenWeChatPay() {
        weChatPay := &WeChatPay{}
        p.PayMap["wechat_pay"] = weChatPay
    }
    
    func (p *Phone) OpenAliPay() {
        aliPay := &AliPay{}
        p.PayMap["ali_pay"] = aliPay
    }
    
     func (p *Phone) OpenPay(name string, pay Pay) {
         p.PayMap[name] = pay
     }
    
    func (p *Phone) PayMoney(name string, money float32) (err error) {
        pay, ok := p.PayMap[name]
        if !ok {
            err = fmt.Errorf("不支持[%s]支付方式", name)
            return
        }
    
        err = pay.pay(1023, money)
        return
    }
    phone

    结构体排序的方法: 

    package main
    
    import (
        "sort"
        "math/rand"
        "fmt"
    )
    
    type Student struct {
        name string
        age int
        score float32
    }
    
    type StudentSlice []*Student
    
    func (p StudentSlice) Len() int {
        return len(p)
    }
    
    func (p StudentSlice) Less(i, j int) bool {
        return p[i].score > p[j].score
    }
    
    func (p StudentSlice) Swap(i, j int)  {
        p[i], p[j] = p[j], p[i]
    }
    
    func main() {
        var studentArr StudentSlice
        for i := 0; i < 10; i++ {
            var s = &Student {
                name: fmt.Sprintf("李%d", i),
                age: rand.Intn(100),
                score: rand.Float32()*100,
            }
            studentArr = append(studentArr, s)
        }    
        sort.Sort(studentArr)  //排序,studentArr实现了Interface接口的方法
        for i := 0; i < len(studentArr); i++{
            fmt.Printf("%#v
    ", studentArr[i])
        }
    }
    View Code

    冒泡排序的接口实现方式:

    package main
    
    
    import (    
        "math/rand"
        "fmt"
    )
    
    type Student struct {
        name string
        age int
        score float32
    }
    
    type StudentSlice []*Student
    
    func (p StudentSlice) Len() int {
        return len(p)
    }
    
    func (p StudentSlice) Less(i, j int) bool {
        return p[i].score > p[j].score
    }
    
    func (p StudentSlice) Swap(i, j int)  {
        p[i], p[j] = p[j], p[i]
    }
    
    func main() {
        var studentArr StudentSlice
        for i := 0; i < 10; i++ {
            var s = &Student {
                name: fmt.Sprintf("李%d", i),
                age: rand.Intn(100),
                score: rand.Float32()*100,
            }
            studentArr = append(studentArr, s)
        }
        
        bubble_sort(studentArr) 
        for i := 0; i < len(studentArr); i++{
            fmt.Printf("%#v
    ", studentArr[i])
        }
    }
    main
    package main
    
    
    type SortInterface interface {
        Len() int
        Less(i, j int) bool
        Swap(i, j int)
    }
    
    
    func bubble_sort(a SortInterface) {
        
            for i := a.Len() -1; i > 0; i-- {
                for j := 0; j < i; j++ {
                    //if a[j] > a[j+1] {
                    if a.Less(j+1, j) {
                        //a[j], a[j+1] = a[j+1], a[j]
                        a.Swap(j, j+1)
                    }
                }
            }
        }
    bubble

    反射

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

    import (“reflect”) 

    两个函数:

    a.reflect.TypeOf(),获取变量的类型,返回reflect.Type类型
    b.reflect.Type.Kind(),获取变量的类型,返回变量的类型(如struct、int)
    c.reflect.ValueOf(),获取变量的值,返回reflect.Value类型
    d.reflect.Value.Kind(),获取变量的类型,返回变量的类型(如struct、int)
    d.reflect.Value.Type(),获取变量的名称,返回变量的名称(如student)
    e.reflect.Value.Interface(),转换成interface{}类型

    2、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
    )
    View Code

    4.获取变量量的值:
      reflect.ValueOf(x).Float()
      reflect.ValueOf(x).Int()
      reflect.ValueOf(x).String()
      reflect.ValueOf(x).Bool()

    package main
    
    
    import (
        "reflect"
        "fmt"
    )
    
    type Student struct {
        Name string
    }
    
    func (s *Student) Set(name string , Age int, Sex int) {
        s.Name = name
    }
    
    func (s *Student) GetName(name string) {
        s.Name = name
    }
    
    
    func getAllMethod(a interface{}) {
        typeInfo := reflect.TypeOf(a)
        num := typeInfo.NumMethod()  //获取结构体有多少个方法,2个
        for i := 0;i <num; i++{
            method := typeInfo.Method(i) //类型的具体方法是什么
            fmt.Println(method)
        }
    }
    
    func getTypeInfo(a interface{}) {
        typeInfo := reflect.TypeOf(a)
        kind := typeInfo.Kind()
        fmt.Println("kind of a:", kind)
    
        num := typeInfo.NumMethod()
        fmt.Println("method num:", num)
    
        method, ok := typeInfo.MethodByName("SetName")
        if !ok {
            fmt.Println("not have method SetName")
        } else {
            fmt.Println(method)
        }
        fmt.Println()
        fmt.Println()
    }
    
    func testGetTypeInfo() {
        var i int
        getTypeInfo(i)  //获取int变量的类型
    
        var stu Student
        getTypeInfo(&stu) //获取结构体的类型
    
        var s [5]int
        getTypeInfo(s)  //获取数组的类型
    }
    
    
    func testGetAllMethod() {
        
        var stu Student
        getAllMethod(&stu)  //获取结构体的方法
    }
    
    func testGetValuInfo() {
        var i int = 100
        valueInfo := reflect.ValueOf(&i)  //valueInfo是一个结构体,要改变值必须传指针进去
    
        valueInfo.Elem().SetInt(200)  //Elem()获取指针指向的变量
        tmp := valueInfo.Interface()  //将结构体转为一个空接口
        val := tmp.(*int)             //将结构体转为原来的值
        fmt.Println("val:", val)
        fmt.Println("val of valueInfo:", valueInfo.Elem().Int())  //200
        fmt.Println("type:", valueInfo.Type())  //int
        fmt.Println("kind:", valueInfo.Kind())  //int
        fmt.Println("i=", i)
    
        var stu Student
        valueInfo = reflect.ValueOf(stu)
        fmt.Println("type:", valueInfo.Type())  //main.Student
        fmt.Println("kind:", valueInfo.Kind())  //类别为struct
    
    }
    
    func main() {
        //testGetTypeInfo()
        //testGetAllMethod()
        testGetValuInfo()
    }
    View Code

    5、通过反射的来改变量的值
       reflect.Value.SetXX相关方法, 比如:
       reflect.Value.SetFloat(),设置浮点数
       reflect.Value.SetInt(),设置整数
       reflect.Value.SetString(),设置字符串

    package main
    
    
    import (
        "fmt"
        "reflect"
    )
    
    
    type Student struct {
        Name string
        Age int
        Sex int
    }
    
    func (s *Student) Set(name string , Age int, Sex int) {
        s.Name = name
        s.Age = Age
        s.Sex = Sex
    }
    
    func (s *Student) GetName(name string) {
        s.Name = name
    }
    
    func testStruct () {
        var stu *Student = &Student{}
        stu.Set("jim", 18, 1)   //结构体赋值
    
        valueInfo := reflect.ValueOf(stu)
    
        fieldNum := valueInfo.Elem().NumField()  //获取结构体中字段的个数
        fmt.Println("field name:", fieldNum)
        sexValueInfo := valueInfo.Elem().FieldByName("Sex") //通过字段名,找到相应的字段,返回的是一个结构体
        fmt.Println("sex=", sexValueInfo.Int())
    
        sexValueInfo.SetInt(100)   //修改sex字段
        fmt.Println(stu)
    
        setMethod := valueInfo.MethodByName("Set")  //调用结构体的方法
        fmt.Println(setMethod)
        
        var params []reflect.Value
        name := "Tom"
        age := 1000
        sex := 3883
    
        params = append(params, reflect.ValueOf(name))
        params = append(params, reflect.ValueOf(age))
        params = append(params, reflect.ValueOf(sex))
    
        setMethod.Call(params)  //调用结构体的方法,params要传一个切片进去
        fmt.Println(stu)
    }
    
    func main() {
        testStruct()
    }
    View Code
  • 相关阅读:
    Load Balancing 折半枚举大法好啊
    Big String 块状数组(或者说平方分割)
    K-th Number 线段树(归并树)+二分查找
    D. Powerful array 莫队算法或者说块状数组 其实都是有点优化的暴力
    CSU OJ PID=1514: Packs 超大背包问题,折半枚举+二分查找。
    运行时Runtime的API
    UIView的API
    UIControl的API
    UIScrollView的API
    使用KVO键值监听
  • 原文地址:https://www.cnblogs.com/domestique/p/8283725.html
Copyright © 2011-2022 走看看