zoukankan      html  css  js  c++  java
  • go语法专题:空接口,反射,空结构体,断言,泛型

    参考:

    https://blog.csdn.net/weixin_44014995/article/details/114596529(go语言的空接口,反射,泛型)

    https://www.jianshu.com/p/6a46fc7b6e5b(go语言的类型断言)

    前言

    go语言就是通过接口interface{}和结构体struct{}组织起来的,interface{}是方法的集合,struct{}是数据结构的集合+接口的实现。

    反射可以动态地获取任意对象的类型及其结构信息。

    空接口的引入

    Go语言打破了传统面向对象编程中类与类之间继承的概念,而是通过组合实现方法和属性的复用,所以不存在类似的继承关系数,也就没有所谓的祖宗类,而且类与接口之间也不再通过implements 关键字强制绑定实现关系,所以 Go 语言的面向对象编程非常灵活。

    在Go语言中,类与接口的实现关系是通过类所实现的方法在编译期推断出来的,如果我们定义一个空接口的话,那么显然所有的类都实现了这个接口,反过来,我们也可以通过空接口来指向任意类型,从而实现类似Java中Object类所承担的功能,而且显然Go的空接口实现更加简洁,通过一个简单的字面量即可完成:

    interface{}

    空接口的基本使用

    指向任意类型变量

    #基本类型
    var v1 interface{} = 1 // 将 int 类型赋值给 interface{} 
    var v2 interface{} = "学院君" // 将 string 类型赋值给 interface{} 
    var v3 interface{} = true  // 将 bool 类型赋值给 interface{}
    
    #复合类型
    var v4 interface{} = &v2 // 将指针类型赋值给 interface{} 
    var v5 interface{} = []int{1, 2, 3}  // 将切片类型赋值给 interface{} 
    var v6 interface{} = struct{   // 将结构体类型赋值给 interface{}
        id int
        name string
    }{1, "学院君"} 

    声明任意类型的参数

    func Printf(fmt string, args ...interface{}) 
    func Println(args ...interface{}) ...
    func (p *pp) printArg(arg interface{}, verb rune)

    反射

    反射三大定律:

    1,反射可以将interface类型变量转换成反射对象

    2,反射可以将反射对象还原成interface对象

    3,反射对象可修改,value值必须是可设置的

    #第一定律
    #TypeOf()和ValueOf()接受的参数都是interface{}类型的,也即x值是被转成了interface传入的。
    var x float64 = 3.4
    t := reflect.TypeOf(x)  //t is reflext.Type
    fmt.Println("type:", t)
    
    v := reflect.ValueOf(x) //v is reflext.Value
    fmt.Println("value:", v)
    
    #第二定律
    #对象x转换成反射对象v,v又通过Interface()接口转换成接口对象,interface对象通过.(float64)类型断言获取float64类型的值。
    var y float64 = v.Interface().(float64)
    fmt.Println("value:", y)
    #第三定律 var x float64 = 3.4 v := reflect.ValueOf(x) #不可修改 v.SetFloat(7.1) // Error: will panic. var x float64 = 3.4 v := reflect.ValueOf(&x) #可修改 v.Elem().SetFloat(7.1) fmt.Println("x :", v.Elem().Interface())

    空结构体

    另外,有的时候你可能会看到空的结构体类型定义:

    struct{}

    表示没有任何属性和成员方法的空结构体,该类型的实例值只有一个,那就是 struct{}{},这个值在 Go 程序中永远只会存一份,并且占据的内存空间是 0,当我们在并发编程中,将通道(channel)作为传递简单信号的介质时,使用 struct{} 类型来声明最好不过。

    断言

    golang中的所有程序都实现了interface{}的接口,这意味着,所有的类型如string,int,int64甚至是自定义的struct类型都就此拥有了interface{}的接口,这种做法和java中的Object类型比较类似。那么在一个数据通过func funcName(interface{})的方式传进来的时候,也就意味着这个参数被自动的转为interface{}的类型。

    1,x.(T)检查x的动态类型是否是T,其中x必须是接口值。

    2,如果接口时具体类型T,对接口值x断言其动态类型是具体类型T,若成功则提取出x的具体值(返回2个值的时候为具体值,true);如果检查失败则panic(返回2个值的时候为零值,false不会返回panic)。

    3,无论T是什么类型,如果x是nil接口值,则类型断言失败。

    4,如果x是接口类型,则T没有要求;如果x是非空接口类型,则T必须是实现了x;

    5,如果接口时接口类型T,类型断言检查x的动态类型是否满足T,如果检查成功,x的动态值不会被提取,返回值是一个类型为T的接口值

    返回两个值

    如果我们想知道类型断言是否失败,而不是失败时触发panic,可以使用返回两个值的版本:

    y, ok := x.(T)
    #举例
    var w io.Writer = os.Stdout
    f, ok := w.(*os.File) //成功:f为os.Stdout,ok为true
    b, ok := w.(*bytes.Buffer) //失败:b为零值,这里是nil, ok为false,no panic

    惯用:

    if f, ok := w.(*os.File); ok {
        // ... use f ...
    }

    使用switch

    func classifier(items ...interface{}) {
        for i, x := range items {
            switch x.(type) {
            case bool:
                fmt.Printf("Param #%d is a bool
    ", i)
            case float64:
                fmt.Printf("Param #%d is a float64
    ", i)
            case int, int64:
                fmt.Printf("Param #%d is a int
    ", i)
            case nil:
                fmt.Printf("Param #%d is a nil
    ", i)
            case string:
                fmt.Printf("Param #%d is a string
    ", i)
            default:
                fmt.Printf("Param #%d is unknown
    ", i)
            }
        }
    }
  • 相关阅读:
    VS2015&windows开发环境配置
    Chapter 12. Classes
    Chapter 11. Generic Algorithms
    Chapter 10. Associative Containers
    Chapter 9. Sequential Containers
    Chapter 8. The IO Library
    Chapter 7. Functions
    Chapter 5. Expressions
    案例分析 极化跳变
    机器如果能够实现自己建模,应该是下一次人工智能的飞跃点
  • 原文地址:https://www.cnblogs.com/tkzc2013/p/15508683.html
Copyright © 2011-2022 走看看