go語言中interface是一種非常重要的型別,是非常重要的組成部分
1、鴨子型別
鴨子型別
當一隻鳥走起來像鴨子,游泳起來像鴨子,叫起來也想鴨子,那這隻鳥就是鴨子
鴨子型別強調的是事物的方法,而不是內部的結構
也就是說,只要一個物件實現了介面的所有方法,那麼這個物件就可以被認為是實現了這個介面,就能將這個物件作為這個介面的例項
2、介面的定義
介面的定義需要用到type和interface關鍵字,具體的定義格式如下:
type 接口名 interface{
方法名1(参数列表) 返回值列表
方法名2(参数列表) 返回值列表
...
}
下面是一個例子:
type Duck interface{
Gaga()
Walk()
Swimming()
}
type pskDuck struct{
legs int
}
func (pd *pskDuck) Gaga(){
fmt.Println("嘎嘎嘎")
}
func (pd *pskDuck) Walk(){
fmt.Println("走")
}
func (pd *pskDuck) Swimming(){
fmt.Println("游泳")
}
func main(){
var duck Duck = &pskDuck{}
duck.Gaga()
duck.Walk()
duck.Swimming()
}
3、多介面實現
在實際的應用場景中,介面不應該寫的太大,一般一個介面只實現一個方法
type Duck interface{
Gaga()
}
type Duck2 interface{
Walk()
}
type Duck3 interface{
Swimming()
}
type pskDuck struct{}
、
func (pd *pskDuck) Gaga(){
fmt.Println("嘎嘎嘎")
}
func (pd *pskDuck) Walk(){
fmt.Println("走")
}
func (pd *pskDuck) Swimming(){
fmt.Println("游泳")
}
func main(){
var duck Duck = &pskDuck{}
var duck2 Duck2 = &pskDuck{}
}
在上面的例子中,pskDuck實現了Duck、Duck2、Duck3三個介面,但是在main函式中,只宣告瞭Duck介面,但是卻可以將pskDuck的例項賦值給Duck介面,這是因為pskDuck實現了Duck介面的所有方法,所以可以將pskDuck的例項賦值給Duck介面
介面也可以作為結構體的引數
介面的使用非常靈活
程式碼的解耦
一個型別實現多個介面。一個介面實現多個型別
……
4、介面與動態型別傳參
斷言
舉個例子,做一個加法計算器:
func add(a, b interface{}) interface{}{
switch a.(type){
case int:
ai, _ := a.(int)
bi, _ := b.(int)
return ai + bi
case int32:
ai, _ := a.(int32)
bi, _ := b.(int32)
return ai + bi
case float32:
ai, _ := a.(float32)
bi, _ := b.(float32)
return ai + bi
//……
default:
return 0
}
}
func main(){
fmt.Println(add(1, 2))
fmt.Println(add(1, 3))
fmt.Println(add(1.0, 2.0))
}
5、介面巢狀
介面巢狀達到程式碼複用的目的
type MyWriter interface{
Write(string)
}
type MyReader interface{
Reader() string
}
type MyReaderWriter interface{
MyReader
MyWriter
ReadWriter()
}
type SreadWriter struct{}
func (srw *SreadWriter) Read(){
fmt.Println("read")
}
func (srw *SreadWriter) Write(){
fmt.Println("write")
}
func (srw *SreadWriter) ReadWriter(){
fmt.Println("readWriter")
}
func main(){
var mrw MyReaderWriter = &SreadWriter{}
mrw.Read()
}
6、介面與slice常見的錯誤
slice不能作為介面的引數,因為slice是一個引用型別,但是介面是一個值型別,所以不能將slice作為介面的引數,但是可以將slice的指標作為介面的引數
func mPrint(data ... interface{}){
for _, value := range data{
fmt.Println(value)
}
}
func main(){
//这样是支持的
var data = []interface{}{
"aaaaa",
19,
1800.00,
}
mPrint(data...)
}