zoukankan      html  css  js  c++  java
  • 接口

    支持匿名接口类型,可直接用为变量定义,或结构体字段
    package main
    
    type data struct {
    }
    
    func (data) string() string {
        return "haha"
    }
    
    type node struct {
        data interface {
            string() string  //匿名接口类型
        }
    }
    
    func main() {
        var t interface {
            string() string //定义匿名接口变量
        } = data{}
        n := node{
            data: t,
        }
        println(n.data.string())
    }
    如果实现接口的类型支持,可做相等运算
    使用反射机制,编写函数的适配器,桥连接**
    test1 := func(v1 int, v2 int){
        t.Log(v1,v2)
    }
    基本介绍
    1. 反射可以在运行时动态获取变量的各种信息,比如变量的类型,类别
    2. 如果是结构体变量,还可以获取到结构体本身的信息(包括字段,方法)
    3. 通过反射可以修改变量的值可以调用关联的方法
    4. 使用反射,需要import("reflect")

    变量 interface{}和reflect.Value是可以相互转换

    func test(b interface{}){
        //如何将interface{}转成reflect.Value
        rval:=reflect.ValueOf(b)l:=reflect.ValueOf(b)
        //如何将reflect.Value ->interface{}
        iVal:=rVal.Interface()
        //如何将interface{}转成原来的变量类型,使用类型断言
        v:=iVal.(Stu)
    }
    反射的基本类型
    func reflectTest01(b interface{})  {
        rTyp := reflect.TypeOf(b)
        rVal := reflect.ValueOf(b)
        fmt.Println(rTyp,rVal) //通过输出的可以看到rVal的值,但是这个值不可以用于运算,因为是relect.Value类型
        n :=  rVal.Int() //通过relect包提供的各种接口可以取到真正的值Int Float String等等
        fmt.Println(n+2)
        iv :=rVal.Interface() //将rVal转成interface{}
    
        num2 := iv.(int) //将interface{}通过断言转成需要的类型
         fmt.Println(num2)
    }

    对结构体的反射

    反射是运行时反射,所以转成接口时在运行时是我们想用的数据,但是如果不断言转换,编译会报错,因为编译时不知道它是什么样的数据

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    type Student struct {
        Name string
        Age  int
    }
    
    type Monster struct {
        Name string
        Age  int
    }
    
    func reflectTest01(b interface{}) {
        rTyp := reflect.TypeOf(b)
        rVal := reflect.ValueOf(b)
           //获取变量对应的kind的两种方法
        //(1) rVal.Kind()
        //(2) rTyp.kind()
        kind1 := rVal.Kind() //kind= struct
        kind2 := rVal.Kind() // kind=struct
        fmt.Printf("kind= %v kind=%v
    ",kind1,kind2)
        fmt.Println(rTyp, rVal) //main.Student {Tom 24} 这里虽然输出是这样,但实际是reflect.Type和reflect.Val类型
        fmt.Printf("%T
    ", rVal) //reflect.Value
        rInter := rVal.Interface()
        //运行时反射,下面语句的输出可以看到这里在运行时就是我们的student实例
        fmt.Printf("%T", rInter) //main.Studenti am student type
        switch rInter.(type) { //可以用switch type来判断是哪种类型
        case Student:
            fmt.Println("i am student type")
        case Monster:
            fmt.Println("i am monster type")
        }
        stu, ok := rInter.(Student) //使用ok模型来防止类型断言出现初五
        if ok {
            fmt.Println(stu.Name) //Tom
        }
    }
    func main() {
        stu := Student{"Tom", 24}
        reflectTest01(stu)
    }
    
    反射的注意事项和细节
    1. reflect.Value.Kind获取变量的类别,返回的是一个常量
    2. Type是类型,kind是类别,Type和Kind可能是相同的,也可能是不同的
      • var sum int = 10 num的Type是int,Kind也是int
      • var stu Student stu的Type是包名.Student, Kind是struct
    通过反射来修改变量
    func reflectTest01(b interface{}) {
        rVal := reflect.ValueOf(b)
        fmt.Printf("rVal kind=%v
    ", rVal.Kind())
        rVal.Elem().SetInt(20) //Elem返回v持有的接口保管的值的Value封装,或者v持有的指针的值得Value封装
    }
    func main() {
        var num int = 10
        reflectTest01(&num)
        fmt.Println("num=", num)
    }
    使用反射来遍历结构体的字段,调用结构体的方法,并获取结构体的值
    package main
    
    import "reflect"
    import "fmt"
    
    type Monster struct {
        Name  string `json:"name"`
        Age   int    `json:"age"`
        Score int
    }
    
    func (s Monster) Print() {
        fmt.Println("--start--")
    }
    func (s Monster) Hello() {
        fmt.Println("--Hello--")
    }
    func (s Monster) GetSum(m, n int) int {
        return m + n
    }
    
    func TestStruct(a interface{}) {
        typ := reflect.TypeOf(a)
        val := reflect.ValueOf(a)
        kd := val.Kind() //获取到a对应的类型
        if kd != reflect.Struct { //如果传入的不是struct,就退出
            fmt.Println("expect struct")
            return
        }
        num := val.NumField() //获取到该结构体有几个字段
        fmt.Printf("Struct has %d fileds
    ", num)
        for i := 0; i < num; i++ {
            //获取到struct标签,注意需要通过reflect.Type来获取tag标签的值
            tagVal := typ.Field(i).Tag.Get("json")
            //如果该字段有标签就显示否则不显示,这里的Score没有做转换,所以打印出来没有它
            if tagVal != "" {
                fmt.Printf("filed %d: tag为%v
    ", i, tagVal)
            }
        }
        //获取到结构体有几个方法
        numOfMethod := val.NumMethod()
        fmt.Printf("Struct has %d methods
    ", numOfMethod)
        var params []reflect.Value //声明了[]reflect.Value
        params = append(params, reflect.ValueOf(10))
        params = append(params, reflect.ValueOf(40))
        res := val.Method(0).Call(params) //获取第一个方法,反射的排序是根据函数名来排序的。H在P前面所以hello是第一个方法}
        fmt.Print(res[0])
    }
    func main() {
        monster := Monster{"牛魔王", 1000, 100}
        TestStruct(monster)
    }
    

    一个结构体如果实现了n个接口的方法,那么它可以赋值给这n个接口

    package main
    
    import "fmt"
    
    type usb interface {
        run()
        walk()
    }
    type phone interface {
        run()
    }
    
    type machine struct {
    }
    
    func (c *machine) run() {
        fmt.Println("hello")
    }
    func (c *machine) walk() {
    
    }
    
    func main() {
        var u usb
        var m *machine
        u = m
        u.run()
    }
    
    




  • 相关阅读:
    [C++]DirectShow检测音视频输入设备及其采集参数
    [C#] 使用Accord.Net,实现相机画面采集,视频保存及裁剪视频区域,利用WriteableBitmap高效渲染
    [C#]使用第三方开源库iText7.pdfHtml,将Html转换成Pdf,以及如何以Html作为打印模板
    C# 佳能相机SDK对接,采集并保存视频,使用WriteableBitmap高效渲染
    wpf常用类型转换器,支持基元类型、可空基元类型、枚举
    wpf单位转换及DPI获取
    使用wpf技术实现画图工具
    InstallShield 创建 visual studio 工程的时候 指向 任意 visual studio 版本 方法 (修改 计算机 默认 visual studio shell 版本)
    WPF ScrollViewer(滚动条) 自定义样式表制作 再发一套样式 细节优化
    C#实现屏幕指定区域截屏
  • 原文地址:https://www.cnblogs.com/hualou/p/12069726.html
Copyright © 2011-2022 走看看