Go的Interface与类型断言学习笔记 | 青训营笔记

320 阅读3分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第8篇笔记。

一、封装

一、认识Interface与断言

1、所有程序都实现了interface{} 的接口(类似于Java中的Object)

  • 所有的类型如string,int,int64甚至是自定义的struct类型都就此拥有了interface{}的接口,这种做法和java中的Object类型比较类似。

那么在一个数据通过func funcName(interface{})的方式传进来的时候,也就意味着这个参数被自动的转为interface{}的类型。

2、Golang的语言中提供了断言的功能。


二、直接断言与判断断言(类型转换)

2.1、错误示范与断言演示

错误示例

比如说我们想要将一个函数中的参数转为string返回,可以尝试如下:

func funcName(a interface{}) string {
    return string(a)
}

不过这个会在编译期间就出现报错

image-20220430235119066

直接断言与判断断言

下面我们来使用直接断言与判断断言两种方式来进行转换:

1、直接断言

package main
​
import "fmt"//1、直接断言方式
func funcName1(a interface{}) string {
    return a.(string)   //直接断言,若是转型失败,则会抛出异常程序结束
}
​
func main() {
    //传入字符串:这个肯定能转型成功
    fmt.Println(funcName1("changlu"))
    //传入数字:这个类型不是string,那么就会
    fmt.Println(funcName1(123))
}

image-20220430235556973

2、判断断言

通过使用两个值来接收,接着来进行判断是否断言成功

package main
​
import "fmt"//2、判断断言
func funcName(a interface{}) string {
    value, ok := a.(string)
    if (!ok) {
        //若是转型失败
        fmt.Println("转型失败")
    }
    return value
}
​
func main() {
    //传入字符串:这个肯定能转型成功
    fmt.Println(funcName("changlu"))
    //传入数字:这个类型不是string,那么就会
    fmt.Println(funcName(123))
}

image-20220430235635516


2.2、类实现多个接口来使用断言转换(实际场景)

案例:将子类实例向上转型接口。(其中也有多态的影子)

package main
​
import "fmt"type reader interface {
    read()
}
​
type writer interface {
    write()
}
​
//实现类,实现了两个接口
type MyFile struct {
}
​
func (this *MyFile) read()  {
    fmt.Println("read ...")
}
​
func (this *MyFile) write()  {
    fmt.Println("write ...")
}
​
​
func main() {
    file := &MyFile{}
    //父类接口引用指向子类实例
    var r reader
    r = file
    r.read()
​
    //通过断言转型为子类实例的另一个writer接口,此时就能够调用write()方法
    w := r.(writer)
    w.write()
}

image-20220501225002105


三、优雅转型方式:switch(及if)

package main
import "fmt"//2、判断断言
func funcName(a interface{}) interface{} {
    //获取类型a.(type)必须写在switch中
    switch t := a.(type) {
        case string:
            fmt.Printf("类型:%T ", t)  //打印类型
            return a.(string)
        case int:
            fmt.Printf("类型:%T ", t)
            return a.(int)
        default:
            fmt.Println("暂无类型转换")
            return nil
    }
}
​
func main() {
    //传入字符串:这个肯定能转型成功
    fmt.Println(funcName("changlu"))
    //传入数字:这个类型不是string,那么就会
    fmt.Println(funcName(123))
}

image-20220501000349979

其他方式就是if了,示例如下,有需要可以去进行仿写

func sqlQuote(x interface{}) string {
    if x == nil {
        return "NULL"
    } else if _, ok := x.(int); ok {
        return fmt.Sprintf("%d", x)
    } else if _, ok := x.(uint); ok {
        return fmt.Sprintf("%d", x)
    } else if b, ok := x.(bool); ok {
        if b {
            return "TRUE"
        }
        return "FALSE"
    } else if s, ok := x.(string); ok {
        return sqlQuoteString(s) // (not shown)
    } else {
        panic(fmt.Sprintf("unexpected type %T: %v", x, x))
    }
}

参考文章

[1] 8、interface与类型断言