• 七、golang中接口、反射


    一、接口定义

    1、定义

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

    package main
    
    import (
       "fmt"
    )
    
    type test interface{
       print()
    }
    
    type Student struct{
       name string
       age int
       score int
    }
    
    func (p *Student)print(){
       fmt.Println("name",p.name)
       fmt.Println("age",p.age)
       fmt.Println("score",p.score)
    }
    
    func main(){
       var t test              //创建接口对象
       var stu Student=Student{   //实例化结构体
          name:"stu1",
          age:20,
          score:100,
       }
       t=&stu     //把实例化传给这个接口对象
       t.print()     //接口对象来调用接口的方法
    }
    name stu1
    age 20
    score 100
    上面的test就是一种类型
    

    多态:

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

    上面的t可以指向Stu,也可以指向其他类型,这个就是多态

    定义:

       比如:

       type  example interface{

             method1(参数列表) 返回值列表

       method2(参数列表) 返回值列表

    }

    interface类型默认是一个指针

    接口实现:

    a、golang中的接口,不需要显示的实现,只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口

    b、如果一个变量含有多个interface类型的方法,那么这个变量就实现了多个接口

    c、要实现变量中接口的所有方法,才是实现了这个接口

    接口嵌套:

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

    type ReadWrite interface{

             Read(b Buffer) bool

             Write(b Buffer)bool

    }

    type Lock interface{

             Lock()

             Unlock()

    }

    type File interface{

             ReadWrite

             Lock

             Close()

    }

    类型断言

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

    var t int              var t int

    var x interface{}    var x interface {}

    x=t              x=t

    y=x.(int)//转成int  y ,ok=x.(int)  //转成int,带检查

    二叉排序树

    时间复杂度和二分查找时间复杂度是一样的

    为什么要使用接口?

    接口是一个规范,不需要关注类等的实现。即,数据本来在mysql里面然后突然变成pg里面,只要接口不变,使用方就不需要更改

    如果接口里面没有任何方法,那么我们就叫这个接口为空接口

    package main
    
    import (
       "fmt"
    )
    
    type Carer interface{
       GetName() string
       Run()
       DIDI()
    }
    
    func main(){
       var car Carer
       fmt.Println(car)  //<nil>
    }
    上面打印出这个接口的值为nil
    

    下面具体接口的用法:

    package main

    import (
       "fmt"
    )

    type Carer interface{
       GetName() string   //这里前面定义的方法,后面代表返回值类型
       Run()
       DIDI()
    }

    type BWM struct{
       Name string
    }

    func (p *BWM)GetName() string{
       return p.Name
    }

    func (p *BWM)Run(){
       fmt.Printf("%s is Running",p.Name)
    }

    func (p *BWM)DIDI(){
       fmt.Printf("%s is didi",p.Name)
    }

    func main(){
       var car Carer
       fmt.Println(car)  //<nil>

       bwm:=BWM{
          Name:"bwm",
       }
       car=&bwm
       car.Run()
    }

    接口操作小结:

    1、定义接口和方法,注意返回值

    2、定义类型

    3、定义类型实现的接口的方法,注意这里要实现接口所有的方法

    4、声明定义的类型,声明接口变量的类型并且初始化,并把定义的类型赋值给接口变量的类型,注意指针

    5、用定义的接口变量执行接口方法

    鸭子类型

    只要实现了接口相关的协议,那么这个就是接口

    如sort只需要实现下面的接口就可以

    func Sort(data Interface) 这里只需要传入接口就可以了

    这个接口实现下面的方法

    type Interface interface{

             Len() int           长度

             Less(I,j int) bool     比较两个数

             Swap(I,j int)        交换两个数

    }

    注意下面的大小写

    package main
    
    import (
       "fmt"
       "math/rand"
    
       "sort"
    )
    
    type Student struct{
       Name string
       Id string
       Age int
    }
    
    type StudentArray []Student  //定义这个是切片结构体
    
    func (p StudentArray) Len() int {
       return len(p)
    }
    
    func (p StudentArray)Less(i,j int)bool{
       return p[i].Name>p[j].Name      //从大到小
    }
    
    func (p StudentArray)Swap(i,j int){
       p[i],p[j]=p[j],p[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.Sort(stus)         
       for _, v := range stus {
          fmt.Println(v)
       }
    }
    

    反射

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

    import (“reflect”)

    两个函数

    a)reflect.TypeOf,获取变量的类型,返回reflect.Type类型

    b)reflect.ValueOf 获取变来那个的值,返回reflect.Value类型

    c) reflect.Value.Kind 获取变量的类别,返回一个变量

    d) reflect.value.Interface()  转换成interface类型

    a和c的区别:

    类型和类别的区别

    类别范围》类型

     

    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)   //main.Student  类型
    
       v:=reflect.ValueOf(b)
       k:=v.Kind()
       fmt.Println(k)    //struct类别
    
       iv:=v.Interface()
       stu,ok:=iv.(Student)
       if ok{
          fmt.Printf("%v %T
    ",stu,stu)//{stu01 18 92} main.Student
       }
    }
    
    func main(){
       var a Student=Student{
          Name:"stu01",
          Age:18,
          Score:92,
       }
       test(a)
    }
    可以在动态运行时的时候的到b的很多信息,这就是反射
    上面是三种转换
    
    下main是获取值
    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)   //main.Student  类型
    
       v:=reflect.ValueOf(b)
       k:=v.Kind()
       fmt.Println(k)    //struct类别
    
       iv:=v.Interface()
       stu,ok:=iv.(Student)
       if ok{
          fmt.Printf("%v %T
    ",stu,stu)//{stu01 18 92} main.Student
       }
    }
    
    func testInt(b interface{}){
       val :=reflect.ValueOf(b)
       c:=val.Int()           //获取值
       fmt.Printf("get value interface{} %d",c)//get value interface{} 1234
    }
    
    func main(){
       var a Student=Student{
          Name:"stu01",
          Age:18,
          Score:92,
       }
       test(a)
       testInt(1234)
    }
    小结:
    1、反射获取具体的了类型
    2、转化为具体的值
    3、.Int()等获取具体的值
    4、才能打印输出值
    

      

  • 相关阅读:
    HDU.4352.XHXJ's LIS(数位DP 状压 LIS)
    AGC 015C.Nuske vs Phantom Thnook(思路 前缀和)
    window下域名解析系统DNS诊断命令nslookup详解
    Nginx入门篇-基础知识与linux下安装操作
    物理服务器Linux下软RAID和UUID方式挂载方法--Megacli64
    Linux下进程与线程的区别及查询方法
    Linux系统下DNS主从配置详解
    CactiEZ中文解决方案和使用教程
    关于MyBase 7.0 破解的方法
    git分支与合并(3)
  • 原文地址:https://www.cnblogs.com/pyrene/p/8094293.html
Copyright © 2020-2023  润新知