接口嵌套 (接口繼承) 一個接口可以嵌套在另外的接口,如下所示
範例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 package mainimport "fmt" type ReadWrite interface { Read() Write() } type Lock interface { Lock() Unlock() } type File interface { ReadWrite Lock close () } func File_operate (f File) { f.Write() f.Read() f.Lock() f.Unlock() f.close () } type Test struct { Name string } func (self Test) Read () { fmt.Println("Read...." ) } func (self Test) Write () { fmt.Println("Write...." ) } func (self Test) Lock () { fmt.Println("File Lock !!" ) } func (self Test) Unlock () { fmt.Println("File Unlock !!" ) } func (self Test) close () { fmt.Println("File close..." ) } func main () { var test Test File_operate(test) }
一種接口類型可放到其他接口類型中
若要實現File
接口,則ReadWrite
及Lock
接口的所有方法及close()方法都必須實現
類似結構體嵌套匿名結構體
result 1 2 3 4 5 Write.... Read.... File Lock !! File Unlock !! File close...
類型斷言 (類型轉換)
由於接口是一般類型 ,並不知道具體類型
任何類型只要滿足a接口內所有的方法,該類型亦為a接口類型
再調用函數時,參數接受a接口類型時,並不知道傳參進來的a接口指向的是何種類型的實例(如上範例)
要是接口指向的是非期望的類型需進行類型轉換 再操作
此時便需做類型斷言
如要轉成具體類型可採用以下方式進行轉換
不安全的類型斷言 1 2 3 4 var t int var x interface {}x = t y = x.(int )
範例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package mainimport "fmt" func add (a interface {}) { b := a.(int ) b += 3 fmt.Println(b) } func main () { a := 100 add(a) }
[1] 要是傳進來的參數不為int
類型時,斷言為int
將會panic
,因此需要安全的類型斷言
安全的類型斷言 在進行斷言之前會先檢查是否能轉換1 2 3 4 var t int var x interface {}x = t y,ok =x.(int )
範例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package mainimport "fmt" func add (a interface {}) { b , ok := a.(int ) if ok == false { fmt.Println("assertion Error" ) return } b += 3 fmt.Println(b) } func main () { a := 1000 add(a) }
判斷傳參的類型(利用switch斷言) 使用switch
判斷傳入參數的類型1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package mainimport ( "fmt" ) func determine_type (a ...interface {}) { for i,x := range a{ switch x.(type ){ case bool : fmt.Println("number" ,i,"type is bool" ) case int : fmt.Println("number" ,i,"type is integer" ) case string : fmt.Println("number" ,i,"type is string" ) case nil : fmt.Println("number" ,i,"type is nil" ) case int64 : fmt.Println("number" ,i,"type is int64" ) case float64 ,float32 : fmt.Println("number" ,i,"type is float" ) default : fmt.Println("I don't know what's the type of" ,i) } } } func main () { determine_type("a" ,int64 (133 ),true ,false ,"abcd" ,'c' ,123456 ,333.3333 ) }
須注意x.(type)
這樣的用法,用來作類型斷言的判斷非常好用
也可用來判斷自定義的類型,如struct
、指針類型等
result 1 2 3 4 5 6 7 8 number 0 type is string number 1 type is int64 number 2 type is bool number 3 type is bool number 4 type is string I don't know what's the type of 5 number 6 type is integer number 7 type is float
tips
類型斷言不一定是只拿某個接口類型的變量判斷是否能轉成其他類型
其他類型的變量也能拿來判斷是否實現了接口 (比較少用)
practice
實現一個可存放任何類型data的鏈表1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 package mainimport "fmt" type data_save struct { data interface {} next *data_save } type record_pointer struct { Head *data_save Tail *data_save } func (self *record_pointer) InsertHead_CreateNode (data interface {}) { Node := &data_save{} Node.data = data if self.Head == nil && self.Tail ==nil { self.Head = Node self.Tail = Node return } Node.next = self.Head self.Head = Node } func (self *record_pointer) InsertTail_CreateNode (data interface {}) { Node := &data_save{} Node.data = data if self.Head == nil && self.Tail ==nil { self.Head = Node self.Tail = Node return } self.Tail.next = Node self.Tail = Node } func (self *record_pointer) view () { var p *data_save = self.Head for p != nil { fmt.Println(*p) p = p.next } } func main () { var a record_pointer for i:=0 ;i<10 ;i++{ a.InsertTail_CreateNode(i) } a.view() }
只要存放的data接受空接口類型(interface{}
) ,就能存放任何類型的變量
result 1 2 3 4 5 6 7 8 9 10 {0 0xc04205a400} {1 0xc04205a420} {2 0xc04205a440} {3 0xc04205a460} {4 0xc04205a480} {5 0xc04205a4a0} {6 0xc04205a4c0} {7 0xc04205a4e0} {8 0xc04205a500} {9 <nil>}