Golang 接口類型 - 下篇
目錄
-
1、接口嵌入
-
1.1 定義
-
1.2 實現
-
1.3 使用
-
2、匿名接口和空接口
-
2.1 匿名接口
-
2.2 空接口
-
2.3 使用場景
-
3、接口斷言和查詢
-
3.1 斷言
-
3.2 查詢
本文是 Golang 接口類型 - 上篇 的續篇內容
1、接口嵌入
和結構體struct
一樣,接口之中也可以嵌入已存在的接口,從而實現接口的擴展
1.1 定義
// Sender 定義Sender接口
type Sender interface {
Send(msg string) error
}
// Receiver 定義Receiver接口
type Receiver interface {
Receive() (string, error)
}
// Client Client,由Sender和Receiver組合
type Client interface {
Sender // 匿名嵌入
Receiver // 匿名嵌入
Open() error
Close() error
}
1.2 實現
// MSNClient 定義MSNClient結構體,並實現Client接口中Open/Send/Receive/Close方法
type MSNClient struct{
}
func (c MSNClient) Open() error {
fmt.Println("Open")
return nil
}
func (c MSNClient) Close() error {
fmt.Println("Close")
return nil
}
func (c MSNClient) Send(msg string) error {
fmt.Println("send:", msg)
return nil
}
func (c MSNClient) Receive() (string, error) {
fmt.Println("Receive")
return "", nil
}
1.3 使用
func main() {
//msn := MSNClient{}
//var s Sender = msn
//var r Receiver = msn
//var c Client = msn
//s.Send("1")
//r.Receive()
//c.Open()
//defer c.Close()
//c.Send("2")
//c.Receive()
var client Client = MSNClient{}
client.Open()
client.Send("Hi")
msg,_ := client.Receive()
fmt.Printf("%q\n", msg)
client.Close()
}
2、匿名接口和空接口
2.1 匿名接口
在定義變量時將類型指定爲接口的函數簽名的接口,此時叫匿名接口,匿名接口常用於初始化一次接口變量的場景
//通過匿名接口聲明接口變量
var closer interface {
Close() error
}
closer = msn
closer.Close()
2.2 空接口
不包含任何函數簽名的接口叫做空接口,空接口聲明的變量可以賦值爲任何類型的變量(任意接口)
-
空接口類型用
interface{}
表示,注意有{}
-
空接口沒有定義任何方法,因此任意類型都實現了空接口
-
func square(x interface{}){}
該函數可以接收任意數據類型 -
slice
的元素、map
的key
和value
都可以是空接口類型
定義語法:interface{}
package main
import "fmt"
type EStruct struct {
}
type Empty interface {
}
func main() {
es := EStruct{}
var e interface{} = 1
fmt.Println(es, e) // {} 1
e = "test"
fmt.Println(e) // test
e = true
fmt.Println(e) // true
e = es
fmt.Println(e) // {}
}
2.3 使用場景
聲明函數參數類型爲interface{}
,用於接收任意類型的變量
package main
import "fmt"
type EStruct struct{
}
func printType(args ...interface{}) {
fmt.Println("------------------------")
for _, arg := range args {
//fmt.Println(arg)
switch v := arg.(type) {
case int:
fmt.Printf("Int: %T %v\n", v, v)
case string:
fmt.Printf("String: %T %v\n", v, v)
default:
fmt.Printf("Other: %T %v\n", v, v)
}
}
}
func main() {
es := EStruct{}
printType(1, "test", true, es)
/*
Int: int 1
String: string test
Other: bool true
Other: main.EStruct {}
*/
}
3、接口斷言和查詢
類型賦值成了接口類型,能否通過某種方式轉換成當時賦值的類型呢?
當父集接口或者類型對象賦值給接口變量後,需要將接口變量重新轉換爲原來的類型,需要使用類型斷言 / 查詢
3.1 斷言
語法:接口變量.(Type)
判斷一個接口能否轉換成具體類型
// 使用類型斷言信息轉換
sender01, ok := ssender.(Sender)
fmt.Printf("%T, %#v, %v\n", sender01, sender01, ok) // *main.WechatSender, &main.WechatSender{ID:""}, true
sender01.SendAll([]string{"張三", "李四"},"你好")
if sender02, ok := ssender.(*WechatSender); ok {
fmt.Printf("%T, %#v, %v\n", sender02, sender02, ok) // *main.WechatSender, &main.WechatSender{ID:""}, true
fmt.Println(sender02.ID)
}
if sender03, ok := ssender.(*EmailSender); !ok {
fmt.Printf("%T, %#v, %v\n", sender03, sender03, false) // *main.EmailSender, (*main.EmailSender)(nil), false
}
3.2 查詢
可以通過switch-case
+接口變量.(type)
查詢變量類型,並選擇對應的分支塊
// 使用類型查詢
sender = &EmailSender{"test"}
switch v := sender.(type) {
case EmailSender:
fmt.Println("EmailSender", v.SmtpAddr)
case *EmailSender:
fmt.Println("*EmailSender", v.SmtpAddr) // *EmailSender test
case *SmsSender:
fmt.Println("*SmsSender", v.SmsAPI)
case *WechatSender:
fmt.Println("*WechatSender", v.ID)
default:
fmt.Printf("error, %#v\n", v)
}
利用斷言判斷數據類型
package main
import "fmt"
func assert(i interface{}) {
switch v := i.(type) {
case int: // v已被轉爲int類型
//v := i.(int)
fmt.Printf("%d\n", v)
// 在 Type Switch語句的case子句中不能使用fallthrough
case float64: // v已被轉爲float64類型
fmt.Printf("%f\n", v)
case byte, uint16, string: // 如果case後面跟多種type,則v還是interface{}類型
fmt.Printf("%T %v\n", i, i)
}
}
func main() {
var i interface{}
var a int
var b float64
var c byte
i = a
assert(i) // 0
i = b
assert(i) // 0.000000
i = c
assert(i) // uint8 0
}
See you ~
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/9O1npLvL7hGC40uH7y12pg