接口是通过定义某些抽象的方法来约束实现者的规则,对于 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语言框架