G

[Golang基础语法] 接口

RoLingG Golang 2024-03-20

接口

  1. 接口是一组包含方法名、参数、返回值的为具体实现的方法的集合。
  2. 它定义的是方法的定义。
  3. 举个例子:

    package main
    
    import "fmt"
    
    type Cock struct {
        Name string
    }
    
    func (c Cock) Sing() {
        fmt.Println(c.Name, "这只鸡在唱歌")
    }
    
    func Sing(c Cock) {
        c.Sing()
    }
    
    func main() {
        c := Cock{Name: "小坤坤"}
        Sing(c)    
    }

    如上述代码,如果有别的结构体有同样的方法想去调用这个接口,那么它会报错,调用不了。

    package main
    
    import "fmt"
    
    // 接口
    type Cock struct {
        Name string
    }
    
    func (c Cock) Sing() {
        fmt.Println(c.Name, "这只鸡在唱歌")
    }
    
    func Sing(c Cock) {
        c.Sing()
    }
    
    type Cat struct {
        Name string
    }
    
    func (c Cat) Sing() {
        fmt.Println(c.Name, "这只猫在唱歌")
    }
    
    func main() {
        co := Cock{Name: "小坤坤"}
        ca := Cat{Name: "缪缪"}
        Sing(co)
        Sing(ca)    //报错,因为Sing这个接口的参数只接受Cock
        //如果我们想用的话,不是ca.Sing(),就是重新定义一个属于Cat的Sing方法。
        //但这样明显操作很繁琐
    }

    所以我们可以定义一个接口:

    package main
    
    import "fmt"
    
    type Cock struct {
        Name string
    }
    
    // 定义一个接口
    type SingInterface interface {
        Sing()
    }
    
    func (c Cock) Sing() {
        fmt.Println(c.Name, "这只鸡在唱歌")
    }
    
    // 有了接口之后,就不指定类型了,直接使用接口。
    // func Sing(c Cock) {
    func Sing(c SingInterface) {
        c.Sing()
    }
    
    type Cat struct {
        Name string
    }
    
    func (c Cat) Sing() {
        fmt.Println(c.Name, "这只猫在唱歌")
    }
    
    func main() {
        co := Cock{Name: "小坤坤"}
        ca := Cat{Name: "缪缪"}
        Sing(co)
        Sing(ca) //当有了接口之后,就不会报错了
    }

    如果要在接口里面用属性的话,要先自己实现一个获取属性的方法:

    package main
    
    import "fmt"
    
    type Cock struct {
        Name string
    }
    
    // 定义一个接口
    type SingInterface interface {
        Sing()
        GetName() string
    }
    
    func (c Cock) Sing() {
        fmt.Println(c.Name, "这只鸡在唱歌")
    }
    
    func (c Cock) GetName() string {
        return c.Name
    }
    
    // 有了接口之后,就不指定类型了,直接使用接口。
    // func Sing(c Cock) {
    func Sing(c SingInterface) { //其实这个时候的名字叫FuncInterface()更好,这个不只是Sing了。
        c.Sing()
        fmt.Println(c.GetName())
    }
    
    type Cat struct {
        Name string
    }
    
    func (c Cat) Sing() {
        fmt.Println(c.Name, "这只猫在唱歌")
    }
    
    func (c Cat) GetName() string {
        return c.Name
    }
    
    func main() {
        co := Cock{Name: "小坤坤"}
        ca := Cat{Name: "缪缪"}
        Sing(co)
        Sing(ca) //当有了接口之后,就不会报错了
    }
    //这样两个相似对象都能用一个接口实现。
    //在相似对象多的时候使用接口,能使代码简洁很多。
  4. 接口本身是不能绑定方法的,它默认是值传递。
  5. 通过接口,我们还可以知道什么类型的值调用了接口。进行类型断言即可。

    func Sing(c SingInterface) {
        ch := c.(Cock)    //断言是Cock类型调用了接口
        fmt.Println(ch)
        c.Sing()
        fmt.Println(c.GetName())
    }
    //其他代码和上面例子相同
    /*
        输出:{小坤坤}
        小坤坤 这只鸡在唱歌
        小坤坤
        panic: interface conversion: main.SingInterface is main.Cat, not main.Cock
    */
    //上面报错可以看出Cat类型被断言失败,是Cat类型不是Cock类型。
    
    func Sing(c SingInterface) {
        ch, ok := c.(Cock)    //用ok查看是否断言成功
        fmt.Println(ch, ok)
        c.Sing()
        fmt.Println(c.GetName())
    }
    //输出:
    /*
        {小坤坤} true
        小坤坤 这只鸡在唱歌
        小坤坤
        {} false
        缪缪 这只猫在唱歌
        缪缪
    */
    //虽然输出不一样了,但还是可以通过bool值ok看出类型断言失败了。

    这还只是断言一种类型,我们可以断言所有类型:

    func Sing(c SingInterface) {
        switch ctype := c.(type) {
        case Cock:
            fmt.Println(ctype)
        case Cat:
            fmt.Println(ctype)
        default:
            fmt.Println("其他")
        }
        c.Sing()
        fmt.Println(c.GetName())
    }
    //输出:
    /*
        {小坤坤}
        小坤坤 这只鸡在唱歌
        小坤坤
        {缪缪}
        缪缪 这只猫在唱歌
        缪缪
    */
    //类型都被断言成功了。
  6. 空接口:没有定义任何方法的接口为空接口。空接口可以接受任何类型。也就是说任何类型都能实现空接口的定义。
  7. 空接口可直接使用作为类型声明的一个实例,这个实例就能承载任何类型的值。
  8. 空接口可以承载任何类型的数组或者切片。但是当空接口承载了数组或者切片以后,这个对象无法再进行切片。
  9. 空接口的类型对象不能赋值给另一个固定类型的对象。
  10. 空接口用的很多,也很重要。例如常用的print就用到了空接口。

    tyep EmptyInterface interface {
    
    }
    func Print(val EmptyInterface){
        fmt.Println(val)
    }

    在简洁点的写法:

    func Print(val interface{}){
        fmt.Println(val)
    }

    甚至再简洁一点:

    func Print(val any){
        fmt.Println(val)
    }
    //其实any就是interface{}的别名
PREV
[Golang基础语法] 网络编程
NEXT
[Golang基础语法] 协程与通道

评论(0)

发布评论