Go基础-接口

91 阅读3分钟

接口是通过定义某些抽象的方法来约束实现者的规则,对于 Go 语言接口之间与接口实现的耦合性比较低,灵活性也比较高

1. 接口定义

接口定义可以使用 interface进行 标识,其声明了一些函数签名 包括(函数名、函数的参数、函数的返回值)

//定义接口
type Sender interface {
    Send (to,msg string)error
    SendAll (tos []string,msg string)error
}

2. 接口声明

声明一个接口变量只需要我们定义其变量类型为接口名,这时变量会被初始化为 nil

    var sender Sender
    fmt.Printf("%T:%v",sender,sender)
​
    //结果
    <nil>:<nil>
    Process finished with exit code 0

3. 赋值

1) 类型对象

当编写的任意类型只要实现了接口类型中声明的所有函数时,则该类型的对象就可以赋值给这个接口变量,并可以使用此接口变量来进行调用实现的接口

a) 方法接收者全为值类型的方法

//定义结构体
type Emailer struct {
    addr string
    port int
    user,password string
}
​
​
func NewEamiler(addr string,port int,user,password string) Emailer  {
    return Emailer{
        addr:    addr,
        port:     port,
        user:     user,
        password: password,
    }
}
​
//接受者为值对象,调用Send
func (sender Emailer)Send (to,msg string)error  {
    fmt.Printf("发送邮件%s,内容%s\n",to,msg)
    return nil
}
//接受者为值对象,调用SendAll
func (sender Emailer)SendAll (tos []string,msg string)error  {
    for _,i := range tos {
        fmt.Printf("发送邮件%s,内容%s\n",i,msg)
    }
    return nil
}
​

赋值

    sender := Emailer{
        addr:     "qq.com",
        port:     80,
        user:     "zhang",
        password: "123456",
    }
​
    sender.Send("wangyi.com","hello")
    sender.SendAll([]string{"360.com","xiaomi.com"},"hello1111")

b) 方法接收者全为指针类型的

//定义结构体
type Emailer struct {
    addr string
    port int
    user,password string
}
​
​
func NewEamiler(addr string,port int,user,password string) *Emailer  {
    return &Emailer{
        addr:    addr,
        port:     port,
        user:     user,
        password: password,
    }
}
​
//接受者为指针对象,调用Send
func (sender *Emailer)Send (to,msg string)error  {
    fmt.Printf("发送邮件%s,内容%s\n",to,msg)
    return nil
}
//接受者为指针对象,调用SendAll
func (sender *Emailer)SendAll (tos []string,msg string)error  {
    for _,i := range tos {
        fmt.Printf("发送邮件%s,内容%s\n",i,msg)
    }
    return nil
}

赋值

    sender := Emailer{
        addr:     "qq.com",
        port:     80,
        user:     "zhang",
        password: "123456",
    }
​
    sender.Send("wangyi.com","hello")
    sender.SendAll([]string{"360.com","xiaomi.com"},"hello1111")

4.匿名嵌入接口

在接口的定义中我们也可以嵌入已经定义好的接口,这样就实现了接口的扩展

package main
​
import "fmt"type Sender interface {
    Send(msg string)error
}
​
type Receiver interface {
    Receive() (string,error)
}
​
type Connect interface {
    Sender
    Receiver
    open() error
    close() error
}
​
type TcpConnect struct {
    addr string
    port string
}
​
func (conn *TcpConnect)Send(msg string)error  {
    fmt.Println("已发送消息")
    fmt.Println(msg)
    return nil
}
​
func (conn *TcpConnect)Receive() (string,error)  {
    fmt.Println("已接收到消息")
    return "", nil
}
​
func (conn *TcpConnect)open() error  {
    fmt.Println("open")
    return nil
}
​
func (conn *TcpConnect)close() error  {
    fmt.Println("close")
    return nil
}
​
func main()  {
    conn := &TcpConnect{
        addr: "127.0.0.1",
        port: "8080",
    }
    conn.Send("hello")
    conn.Receive()
    conn.open()
    conn.close()
}

结果

已发送消息
hello
已接收到消息
open
close
​
Process finished with exit code 0

5. 匿名接口

在定义某个变量时类型指定为接口的函数的接口,叫做匿名接口,匿名接口一般我们用在形参上使用

    var opener interface{
        open()error
    }
    fmt.Printf("%T,%#v\n",opener,opener)

6. 空接口

使用空接口所声明的变量可以为任何类型的变量进行赋值操作,我们不需要定义参数的类型

package main
​
import "fmt"func PrintType(arg ...interface{})  {
    for _,v := range arg{
        switch v.(type) {
        case nil:
            fmt.Println("nil")
        case int:
            fmt.Println("int")
        case string:
            fmt.Println("string")
        default:
            fmt.Println("error")
        }
    }
}
​
func main()  {
    PrintType(1)
    PrintType("aa")
}

结果

int
string
​
Process finished with exit code 0

本文正在参加技术专题18期-聊聊Go语言框架