接口
在 Go 語言中,接口是一種抽象的類型,是一組方法的集合。接口存在的目的是定義規範,而規範的細節由其他對象去實現。我們來看一個例子:
import "fmt"
type Person struct {
Name string
}
func main() {
person := Person{Name: "cmy"}
fmt.Println(person) // {cmy}
}
上述代碼定義了結構體 Person ,main 函數創建了此結構體的變量 person,然後通過 fmt 包裏的 Println 函數打印這個結構體,打印結果為 {cmy}。在此基礎上,我們改造一下代碼:
import "fmt"
type Person struct {
Name string
}
func (p Person) String() string {
return fmt.Sprintf("name: %s", p.Name)
}
func main() {
person := Person{Name: "cmy"}
fmt.Println(person) // name: cmy
}
新改造的代碼裏為結構體 Person 添加一個結構體方法 String() string,方法的返回結果是對 name 進行格式化,我們再打印一下結構體,觀察結果發現是 String() 方法返回的值,而不是 {cmy}。
為什麼是這樣呢?這是因為 fmt.Println(T) 函數的實現細節裏,會對結構體進行判斷,如果結構體實現了 Stringer 接口,則會直接打印 String() 方法的返回值。以下是 Stringer 接口的代碼:
type Stringer interface {
String() string
}
結構體實現了這個接口,也就意味着遵守這個接口所定義的規範,fmt.Println(T) 函數發現結構體有這個規範,因此就會根據規範來打印信息。基於 Stringer 接口,我們來看看接口的語法格式:
type XXX interface {
// methods
}
-
1、
type接口的聲明,必須以
type關鍵字開頭。 -
2、接口名
推薦駝峯式命名法,首字母大寫的方法名可以在包外訪問,小寫的只能在包內訪問。
-
3、
interface接口的標識。
-
4、接口體
大括號裏面聲明規範,也就是聲明方法,方法必須具有名字。
接口的實現
- 在
Go語言裏,接口的實現不是基於接口,而是基於方法。如果一個自定義類型擁有了某個接口的所有方法,那麼這個自定義類型就實現這個接口。接口的實現在上述的例子中有所體現,Person結構體定義了String() string方法,擁有了Stringer接口的所有方法,因此實現了Stringer接口。 -
一個自定義類型可以實現多個接口
type A interface { a() } type B interface { b() } type Person struct { Name string } func (p Person) a() { } func (p Person) b() { }A接口聲明瞭a方法,B接口聲明瞭b方法,Person結構體定義了a和b兩個方法,因此Person結構體實現了A和B兩個接口。
接口類型變量
一旦接口被定義,它就可以用於聲明變量。
import "fmt"
type A interface {
}
func main() {
var a A
fmt.Println(a) // <nil>
}
如果只聲明接口變量,不初始化,變量的值默認為 nil,因為接口類型實際上是一個指針。若為接口賦初值,需要選擇一個合法的值,即被賦值的基類必須實現這個接口。
空接口
在 Go 語言裏面可以認為所有類型實現了空接口,因為空接口沒有任何的方法。
import "fmt"
type EmptyInterface interface {
}
func main() {
var a EmptyInterface = 1
var b EmptyInterface = true
var c EmptyInterface = "hello"
var d EmptyInterface = 3.14
var e EmptyInterface = 'c'
fmt.Println(a, b, c, d, e) // 1 true hello 3.14 99
}
所有類型都實現空接口,因此空接口變量可以被賦初值為任意類型的值或變量。
類型斷言
Go 語言支持類型斷言操作,通過這個操作,可以還原接口變量的右值(被賦的初值)。類型斷言的語法形式通常為:
v, ok := a.(T)
如果斷言成功,那麼 v 的值為接口變量的值,ok 的值為 true;如果斷言失敗,v 的值為 T 類型的零值,ok 的值為 false。
類型斷言變種 type switch
通過 type switch 的方式,可以判斷接口變量屬於哪種動態類型。
import "fmt"
type EmptyInterface interface {
}
func main() {
var a EmptyInterface = 1
switch a.(type) {
case string:
fmt.Println("a 的右值類型為 string")
case int:
fmt.Println("a 的右值類型為 int")
case bool:
fmt.Println("a 的右值類型為 bool")
case float64:
fmt.Println("a 的右值類型為 float64")
}
}
小結
本文先是對接口的定義進行介紹,然後通過一個例子,瞭解了接口其中的一個應用場景和引出接口的語法格式以及實現的方法,然後介紹了空接口的特點和類型斷言,最後介紹了變種的類型斷言 type switch 的應用例子。
本文參與了SegmentFault 思否寫作挑戰賽活動,歡迎正在閲讀的你也加入。