Golang介面型別-下篇

本文是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 ~
「其他文章」
- Gradle打包工具入門
- 服務網格和Istio初識-續
- 服務網格和Istio初識
- Golang與非對稱加密
- ack叢集Terway網路場景下的vSwitch擴容
- Golang與對稱加密
- 基於ack k8s叢集排程的方案設計
- 基於Dockerfile構建容器映象的最佳實踐
- Golang反射-下篇
- Golang反射-上篇
- Azure DevOps的使用入門
- Golang介面型別-下篇
- Golang介面型別-上篇
- 基於Python實現原生的登入驗證碼
- Golang開發命令列工具之flag包的使用
- Golang檔案操作-下篇
- k8s環境下處理容器時間問題的多種姿勢
- Golang基準測試
- 淺談Prometheus的資料儲存
- Golang單元測試