Go接口是一種數據類型,它把全部的具備共性的方法定義在一塊兒,任何其餘類型只要實現了這些方法就是實現了這個接口。數組
在 go 語言中,接口有下面幾個特色:bash
利用關鍵字 interface 來定義一個接口,接口是一組方法的集合。
接口定義格式:函數
type 接口名稱 interface{
方法名稱1(可能會用到的參數,可不傳) 返回類型
方法名稱2(可能會用到的參數,可不傳) 返回類型
...
}
複製代碼
例如:ui
type People interface {
Show(name string, age int) (id int, err error)
Set(name string, age int)
}
複製代碼
在 go 語言中,接口的實現是隱式的,不須要顯示聲明實現了接口,當一個類型爲接口中的全部方法提供定義時,它被稱爲實現該接口。
接口的實現示例以下:this
package main
import (
"fmt"
)
type USB interface {
Name() string
Connect()
}
type PhoncConnecter struct {
name string
}
// 由於如下方法 Name()、Connect() 與接口USB的方法相同,所以結構體PhoncConnecter實現了USB接口
func (pc PhoncConnecter) Name() string {
return pc.name
}
func (pc PhoncConnecter) Connect() {
fmt.Println(pc.name)
}
func main() {
// 第一種直接在聲明結構時賦值
var a USB // 聲明一個接口類型的變量
a = PhoncConnecter{"PhoneC"} // 由於 PhoncConnecter 實現了接口 USB,因此能夠將該類型的實例賦給接口的變量
a.Connect()
// 第二種,先給結構賦值後在將值給接口去調用
var b = PhoncConnecter{}
b.name = "b"
var c USB // 聲明一個接口類型的變量
c = b
c.Connect()
}
複製代碼
輸出爲:spa
PhoneC
b
複製代碼
以上示例定義了USB的接口,並聲明瞭兩個方法 Name()、Connect()
,接着定義了PhoncConnecter
結構並聲明瞭一個name
的變量,經過方法特性,對結構也一樣聲明瞭兩個方法Name()、Connect()
。在GO中,只要實現了接口中定義的方法,默認就表明相似於其它語言中的繼承,繼承了那個接口,因此在main函數中,就能夠經過聲明接口和結構進行相對應的操做,從而達到代碼重複使用。code
一個接口能夠被認爲是由一個元組(類型,值)在內部表示的。type是接口的基礎具體類型,value是具體類型的值。對象
接口是一系列接口的集合,是一種抽象數據類型,接口變量能夠引用任何實現了接口的所有方法的具體數據類型的值。繼承
接口變量存儲了兩部分信息,一個是分配給接口變量的具體值(接口實現者的值),一個是值的類型的描述器(接口實現者的類型),形式是(value, concrete type),而不是(value, interface type)。接口
package main
import (
"fmt"
)
type Test interface {
Tester()
}
type MyFloat float64
func (m MyFloat) Tester() {
fmt.Println(m)
}
func describe(t Test) {
fmt.Printf("Interface 類型: %T , 值: %v\n", t, t)
}
func main() {
var t Test
f := MyFloat(89.7)
t = f
describe(t)
t.Tester()
}
複製代碼
運行結果:
Interface 類型: main.MyFloat , 值: 89.7
89.7
複製代碼
空接口就是不包含任何方法的接口,它表示爲 interface {}
。正由於如此,全部的類型都實現了空接口。
雖然空接口起不到任何做用,可是空接口在須要存儲任何類型數值的時候很是有用,由於空接口能夠存儲任意類型的數據。
package main
import (
"fmt"
)
func describe(i interface{}) {
fmt.Printf("Type = %T, value = %v\n", i, i)
}
func main() {
// 任何類型的變量傳入均可以
s := "Hello World"
i := 55
strt := struct {
name string
}{
name: "Naveen R",
}
describe(s)
describe(i)
describe(strt)
}
複製代碼
運行結果:
Type = string, value = Hello World
Type = int, value = 55
Type = struct { name string }, value = {Naveen R}
複製代碼
interface{}
可用於向函數傳遞任意類型的變量,但對於函數內部,該變量仍然爲 interface{}
類型(空接口類型),而不是傳入的實參類型。
接口類型向普通類型的轉換稱爲類型斷言(運行期肯定),類型斷言用於提取接口的基礎值,語法:i.(T)
func printArray(arr interface{}){
// arr 是空接口,不是數組類型,報錯
for _, v: = range arr{
fmt.Print(v," ")
}
  fmt.Println()
}
複製代碼
能夠經過類型斷言將接口類型轉換爲切片類型
func printArray(arr interface{}){
// 經過斷言實現類型轉換
a,_ := arr.([]int)
for _,v:=range a{
fmt.Println(v, " ")
}
fmt.Println()
}
複製代碼
在使用類型斷言時,最好判斷斷言是否成功
b,ok := a.(T)
if ok {
...
}
複製代碼
類型判斷的語法相似於類型斷言,在類型斷言的語法i.(type)
中,類型 type 應該由類型轉換的關鍵字 type
替換。 類型斷言能夠配合switch語句進行判斷:
package main
import (
"fmt"
)
func findType(i interface{}) {
switch i.(type) {
case string:
fmt.Printf("String: %s\n", i.(string))
case int:
fmt.Printf("Int: %d\n", i.(int))
default:
fmt.Printf("Unknown type\n")
}
}
func main() {
findType("Naveen")
findType(77)
findType(89.98)
}
複製代碼
運行結果:
String: Naveen
Int: 77
Unknown type
複製代碼
一個接口能夠包含一個或多個其餘的接口,這至關於直接將這些內嵌接口的方法列舉在外層接口中同樣。
好比接口 File 包含了 ReadWrite 和 Lock 的全部方法,它還額外有一個 Close() 方法。
type ReadWrite interface {
Read(b Buffer) bool
Write(b Buffer) bool
}
type Lock interface {
Lock()
Unlock()
}
type File interface {
ReadWrite
Lock
Close()
}
複製代碼
能夠將一個實現接口的對象實例賦值給接口,也能夠將另一個接口賦值給接口。
經過對象實例賦值
若是一個類型實現了某個接口,能夠將類型的實例賦值給接口變量
經過接口賦值
接口A和接口B,若是接口A是接口B的子集,B類型的變量賦給A類型的變量
package main
import (
"bytes"
"io"
"os"
// "time"
)
func main() {
// File、bytes.Buffer 實現了Writer
var w io.Writer // A
w = os.Stdout
w = new (bytes.Buffer)
// w = time.Second // error, 由於time.Second沒有實現了Writer
var rwc io.ReadWriteCloser // B
rwc = os.Stdout // File 實現了 io.ReadWriteCloser 接口
w = rwc
}
複製代碼
go 語言多態是將實現接口的不一樣類型的實例賦給接口變量,讓接口的方法擁有不一樣的行爲。
package main
import "fmt"
type MyGreeting interface {
Greet(name string) string
}
type EnglishGreeting struct {
}
type ChinesGreeting struct {
}
func (this *EnglishGreeting) Greet(name string) string {
return "Hello " + name
}
func (this *ChinesGreeting) Greet(name string) string {
return "你好 " + name
}
func main() {
var greet MyGreeting = new(EnglishGreeting)
fmt.Println(greet.Greet("Bill"))
greet = new(ChinesGreeting)
fmt.Println(greet.Greet("Bill"))
}
複製代碼
運行結果:
Hello Bill
你好 Bill
複製代碼