接口、反射

接口

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\n", index)
        case int32:
            fmt.Printf("第 %d 个参数 is int32\n", index)
        case float32:
            fmt.Printf("第 %d 个参数 is float32\n", 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\n")
    case *Cat:
        t.Eat()
        fmt.Printf("t is cat\n")
    }
}

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\n”, 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\n", err)
         fmt.Printf("使用支付宝支付\n")
         err = phone.PayMoney("ali_pay", 20.32)
         if err != nil {
            fmt.Printf("支付失败,失败原因:%v\n", 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\n", 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\n", 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

 

posted @ 2018-01-14 17:12  shy车队破风手  阅读(266)  评论(0编辑  收藏  举报