亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Golang接口使用教程詳解

 更新時間:2022年09月30日 15:04:58   作者:Leefs  
在?Go?語言中接口包含兩種含義:它既是方法的集合,?同時還是一種類型并且在Go?語言中是隱式實現(xiàn)的。本文通過示例詳細介紹了Golang接口的使用,需要的可以參考一下

前言

go語言并沒有面向對象的相關概念,go語言提到的接口和java、c++等語言提到的接口不同,它不會顯示的說明實現(xiàn)了接口,沒有繼承、子類、implements關鍵詞。

一、概述

在 Go 語言中接口包含兩種含義:它既是方法的集合, 同時還是一種類型。在Go 語言中是隱式實現(xiàn)的,意思就是對于一個具體的類型,不需要聲明它實現(xiàn)了哪些接口,只需要提供接口所必需的方法。

go語言通過隱性的方式實現(xiàn)了接口功能,相對比較靈活。

Go語言接口的特點

  • interface 是方法或行為聲明的集合
  • interface接口方式實現(xiàn)比較隱性,任何類型的對象實現(xiàn)interface所包含的全部方法,則表明該類型實現(xiàn)了該接口。
  • interface還可以作為一種通用的類型,其他類型變量可以給interface聲明的變量賦值。
  • interface 可以作為一種數(shù)據(jù)類型,實現(xiàn)了該接口的任何對象都可以給對應的接口類型變量賦值。

二、接口類型

2.1 接口的定義

每個接口類型由任意個方法簽名組成,接口的定義格式如下:

type 接口類型名 interface{
    方法名1( 參數(shù)列表1 ) 返回值列表1
    方法名2( 參數(shù)列表2 ) 返回值列表2
    …
}

說明

  • 接口類型名:使用 type 將接口定義為自定義的類型名。Go語言的接口在命名時,一般會在單詞后面添加 er,如有寫操作的接口叫 Writer,有字符串功能的接口叫 Stringer,有關閉功能的接口叫 Closer 等。接口名最好要能突出該接口的類型含義。
  • 方法名:當方法名首字母是大寫時,且這個接口類型名首字母也是大寫時,這個方法可以被接口所在的包(package)之外的代碼訪問。
  • 參數(shù)列表、返回值列表:參數(shù)列表和返回值列表中的參數(shù)變量名可以被忽略。

舉個例子,定義一個包含Write方法的Writer接口。

type writer interface{
    Write([]byte) error
}

2.2 實現(xiàn)接口的條件

接口就是規(guī)定了一個需要實現(xiàn)的方法列表,在 Go 語言中一個類型只要實現(xiàn)了接口中規(guī)定的所有方法,那么我們就稱它實現(xiàn)了這個接口。

示例

定義的Eater接口類型,它包含一個Eat方法。

// Eater 接口
type Eater interface {
	Eat()
}

有一個Dog結構體類型如下。

type Dog struct {}

因為Eater接口只包含一個Eat方法,所以只需要給Dog結構體添加一個Eat方法就可以滿足Eater接口的要求。

//Dog類型的Eat方法
func (d Dog) Eat() {
	fmt.Println("吃骨頭!")
}

這樣就稱為Dog實現(xiàn)了Eater接口。

完整代碼

// Eater 接口
type Eater interface {
	Eat()
}

type Dog struct {}

//Dog類型的Eat方法
func (d Dog) Eat() {
	fmt.Println("吃骨頭!")
}

func main() {
	dog := Dog{}
	dog.Eat()
}

2.3 為什么需要接口

多數(shù)情況下,數(shù)據(jù)可能包含不同的類型,卻會有一個或者多個共同點,這些共同點就是抽象的基礎。

示例

// Eater 接口
type Eater interface {
	Eat()
}

type Dog struct {}

//Dog類型的Eat方法
func (d Dog) Eat() {
	fmt.Println("狗狗喜歡吃骨頭!")
}

type Cat struct {}

func (c Cat) Eat(){
	fmt.Println("小貓喜歡吃魚!")
}

func main() {
	dog := Dog{}
	dog.Eat()
	cat := Cat{}
	cat.Eat()
}

從動物身上,可以抽象出來一個eat方法,這樣即使在擴展其它動物進來,也只需要實現(xiàn)Eater 接口中的Eat()方法就可以完成對這個動作的調(diào)用。

接口可以理解為某一個方面的抽象,可以是多對一的(多個類型實現(xiàn)一個接口),這也是多態(tài)的體現(xiàn)。

2.4 接口類型變量

一個接口類型的變量能夠存儲所有實現(xiàn)了該接口的類型變量。

例如在上面的示例中,DogCat類型均實現(xiàn)了Eater接口,此時一個Eater類型的變量就能夠接收CatDog類型的變量。

var x Eater // 聲明一個Eater類型的變量x
a := Cat{}  // 聲明一個Cat類型變量a
b := Dog{}  // 聲明一個Dog類型變量b
x = a       // 可以把Cat類型變量直接賦值給x
x.Eat()     // 小貓喜歡吃魚!
x = b       // 可以把Dog類型變量直接賦值給x
x.Eat()     // 狗狗喜歡吃骨頭!

三、值接收者和指針接收者

通過下方一個示例來演示實現(xiàn)接口使用值接收者和使用指針接收者有什么區(qū)別。

定義一個Mover接口,它包含一個Move方法。

// Mover 定義一個接口類型
type Mover interface {
	Move()
}

3.1 值接收者實現(xiàn)接口

我們定義一個Dog結構體類型,并使用值接收者為其定義一個Move方法。

// Dog 狗結構體類型
type Dog struct{}

// Move 使用值接收者定義Move方法實現(xiàn)Mover接口
func (d Dog) Move() {
	fmt.Println("狗會動")
}

此時實現(xiàn)Mover接口的是Dog類型。

var x Mover    // 聲明一個Mover類型的變量x

var d1 = Dog{} // d1是Dog類型
x = d1         // 可以將d1賦值給變量x
x.Move()

var d2 = &Dog{} // d2是Dog指針類型
x = d2          // 也可以將d2賦值給變量x
x.Move()

從上面的代碼中我們可以發(fā)現(xiàn),使用值接收者實現(xiàn)接口之后,不管是結構體類型還是對應的結構體指針類型的變量都可以賦值給該接口變量。

3.2 指針接收者實現(xiàn)接口

我們再來測試一下使用指針接收者實現(xiàn)接口有什么區(qū)別。

// Cat 貓結構體類型
type Cat struct{}

// Move 使用指針接收者定義Move方法實現(xiàn)Mover接口
func (c *Cat) Move() {
	fmt.Println("貓會動")
}

此時實現(xiàn)Mover接口的是*Cat類型,我們可以將*Cat類型的變量直接賦值給Mover接口類型的變量x

var c1 = &Cat{} // c1是*Cat類型
x = c1          // 可以將c1當成Mover類型
x.Move()

但是不能給將Cat類型的變量賦值給Mover接口類型的變量x。

// 下面的代碼無法通過編譯
var c2 = Cat{} // c2是Cat類型
x = c2         // 不能將c2當成Mover類型

由于Go語言中有對指針求值的語法糖,對于值接收者實現(xiàn)的接口,無論使用值類型還是指針類型都沒有問題。但是我們并不總是能對一個值求址,所以對于指針接收者實現(xiàn)的接口要額外注意。

四、類型與接口的關系

4.1 一個類型實現(xiàn)多個接口

一個類型可以同時實現(xiàn)多個接口,而接口間彼此獨立,不知道對方的實現(xiàn)。

示例

動物不僅有吃的屬性,還有動的屬性,可以通過定義兩個接口,讓同一個動物分別實現(xiàn)這兩種屬性

// Eater 接口
type Eater interface {
	Eat()
}

// Mover 接口
type Mover interface {
	Move()
}

type Dog struct {}

//Dog類型的Eat方法
func (d Dog) Eat() {
	fmt.Println("狗狗喜歡吃骨頭!")
}

//Dog類型的Move方法
func (d Dog) Move(){
	fmt.Println("狗狗喜歡玩耍!")
}

func main() {
	//初始化結構體
	dog := Dog{}

	//dog實現(xiàn)了Eater和Mover兩個接口
	eat := dog
	move := dog

	eat.Eat()	//對Eater類型調(diào)用Eat方法
	move.Move()	//對Mover類型調(diào)用Move方法
}

程序中的結構體Dog分別實現(xiàn)了Eater和Mover兩個接口中的方法。

4.2 多種類型實現(xiàn)同一接口

Go語言中不同的類型還可以實現(xiàn)同一接口。

一個接口的所有方法,不一定需要由一個類型完全實現(xiàn),接口的方法可以通過在類型中嵌入其他類型或者結構體來實現(xiàn)。

// WashingMachine 洗衣機
type WashingMachine interface {
	wash()
	dry()
}

// 甩干器
type dryer struct{}

// 實現(xiàn)WashingMachine接口的dry()方法
func (d dryer) dry() {
	fmt.Println("甩一甩")
}

// 洗衣機
type haier struct {
	dryer //嵌入甩干器
}

// 實現(xiàn)WashingMachine接口的wash()方法
func (h haier) wash() {
	fmt.Println("洗刷刷")
}

func main() {
	h := haier{}
	h.dry()
	h.wash()
}

五、接口嵌套

接口與接口之間可以通過互相嵌套形成新的接口類型。例如Go標準庫io源碼中就有很多接口之間互相組合的示例。

// src/io/io.go

type Reader interface {
	Read(p []byte) (n int, err error)
}

type Writer interface {
	Write(p []byte) (n int, err error)
}

type Closer interface {
	Close() error
}

// ReadWriter 是組合Reader接口和Writer接口形成的新接口類型
type ReadWriter interface {
	Reader
	Writer
}

// ReadCloser 是組合Reader接口和Closer接口形成的新接口類型
type ReadCloser interface {
	Reader
	Closer
}

// WriteCloser 是組合Writer接口和Closer接口形成的新接口類型
type WriteCloser interface {
	Writer
	Closer
}

對于這種由多個接口類型組合形成的新接口類型,同樣只需要實現(xiàn)新接口類型中規(guī)定的所有方法就算實現(xiàn)了該接口類型。

接口也可以作為結構體的一個字段,我們來看一段Go標準庫sort源碼中的示例。

// src/sort/sort.go

// Interface 定義通過索引對元素排序的接口類型
type Interface interface {
    Len() int
    Less(i, j int) bool
    Swap(i, j int)
}


// reverse 結構體中嵌入了Interface接口
type reverse struct {
    Interface
}

通過在結構體中嵌入一個接口類型,從而讓該結構體類型實現(xiàn)了該接口類型,并且還可以改寫該接口的方法。

// Less 為reverse類型添加Less方法,重寫原Interface接口類型的Less方法
func (r reverse) Less(i, j int) bool {
	return r.Interface.Less(j, i)
}

Interface類型原本的Less方法簽名為Less(i, j int) bool,此處重寫為r.Interface.Less(j, i),即通過將索引參數(shù)交換位置實現(xiàn)反轉。

在這個示例中還有一個需要注意的地方是reverse結構體本身是不可導出的(結構體類型名稱首字母小寫),sort.go中通過定義一個可導出的Reverse函數(shù)來讓使用者創(chuàng)建reverse結構體實例。

func Reverse(data Interface) Interface {
	return &reverse{data}
}

這樣做的目的是保證得到的reverse結構體中的Interface屬性一定不為nil,否者r.Interface.Less(j, i)就會出現(xiàn)空指針panic。

六、空接口

Golang 中的接口可以不定義任何方法,沒有定義任何方法的接口就是空接口。空接口表示沒有任何約束,因此任何類型變量都可以實現(xiàn)空接口。

空接口在實際項目中用的是非常多的,用空接口可以表示任意數(shù)據(jù)類型。

示例

func main() {
	//定義一個空接口x,x變量可以接收任意的數(shù)據(jù)類型
	var x interface{}
	str := "Hello Go"
	x = str
	fmt.Printf("type:%T,value:%v\n",x,x)

	num := 10
	x = num
	fmt.Printf("type:%T,value:%v\n",x,x)

	bool := true
	x = bool
	fmt.Printf("type:%T,value:%v\n",x,x)
}

運行結果

type:string,value:Hello Go
type:int,value:10
type:bool,value:true

1、空接口作為函數(shù)的參數(shù)

// 空接口作為函數(shù)參數(shù)
func show(a interface{}) {
	fmt.Printf("type:%T value:%v\n", a, a)
}

func main() {
	show(1)
	show(true)
	show(3.14)
	var mapStr = make(map[string]string)
	mapStr["name"] = "Leefs"
	mapStr["age"] = "12"
	show(mapStr)
}

運行結果

type:int value:1
type:bool value:true
type:float64 value:3.14
type:map[string]string value:map[age:12 name:Leefs]

2、map的值實現(xiàn)空接口

func main() {
	// 空接口作為 map 值
	var studentInfo = make(map[string]interface{})
	studentInfo["name"] = "Jeyoo"
	studentInfo["age"] = 18
	studentInfo["married"] = false
	fmt.Println(studentInfo)
}

運行結果

map[age:18 married:false name:Jeyoo]

3、切片實現(xiàn)空接口

func main() {
	var slice = []interface{}{"Jeyoo", 20, true, 32.2}
	fmt.Println(slice)
}

運行結果

[Jeyoo 20 true 32.2]

七、類型斷言

一個接口的值(簡稱接口值)是由一個具體類型和具體類型的值兩部分組成的。這兩部分分別稱為接口的動態(tài)類型和動態(tài)值。

如果我們想要判斷空接口中值的類型,那么這個時候就可以使用類型斷言,其語法格式:

x.(T)

說明

  • x: 表示類型為 interface{}的變量
  • T: 表示斷言 x 可能是的類型

該語法返回兩個參數(shù),第一個參數(shù)是 x 轉化為 T 類型后的變量,第二個值是一個布爾值,若為 true 則表示斷言成功,為 false 則表示斷言失敗。

示例

func main() {
	var x interface{}
	x = "Hello GO"
	v, ok := x.(string)
	if ok {
		fmt.Println(v)
	} else {
		fmt.Println("類型斷言失敗")
	}
}

上面的示例中如果要斷言多次就需要寫多個 if 判斷,這個時候我們可以使用 switch 語句來 實現(xiàn):

注意:類型.(type)只能結合 switch 語句使用

// justifyType 對傳入的空接口類型變量x進行類型斷言
func justifyType(x interface{}) {
	switch v := x.(type) {
	case string:
		fmt.Printf("x is a string,value is %v\n", v)
	case int:
		fmt.Printf("x is a int is %v\n", v)
	case bool:
		fmt.Printf("x is a bool is %v\n", v)
	default:
		fmt.Println("unsupport type!")
	}
}

由于接口類型變量能夠動態(tài)存儲不同類型值的特點,所以很多初學者會濫用接口類型(特別是空接口)來實現(xiàn)編碼過程中的便捷。

只有當有兩個或兩個以上的具體類型必須以相同的方式進行處理時才需要定義接口。切記不要為了使用接口類型而增加不必要的抽象,導致不必要的運行時損耗。

總結

在 Go 語言中接口是一個非常重要的概念和特性,使用接口類型能夠實現(xiàn)代碼的抽象和解耦,也可以隱藏某個功能的內(nèi)部實現(xiàn),但是缺點就是在查看源碼的時候,不太方便查找到具體實現(xiàn)接口的類型。

相信很多讀者在剛接觸到接口類型時都會有很多疑惑,請牢記接口是一種類型,一種抽象的類型。區(qū)別于我們在之前章節(jié)提到的那些具體類型(整型、數(shù)組、結構體類型等),它是一個只要求實現(xiàn)特定方法的抽象類型。

以上就是Golang接口使用教程詳解的詳細內(nèi)容,更多關于Golang接口的資料請關注腳本之家其它相關文章!

相關文章

  • Go語言基礎學習教程

    Go語言基礎學習教程

    這篇文章主要介紹了Go語言基礎知識,包括基本語法、語句、數(shù)組等的定義與用法,需要的朋友可以參考下
    2016-07-07
  • Go語言中的函數(shù)詳解

    Go語言中的函數(shù)詳解

    函數(shù)是基本的代碼塊,用于執(zhí)行一個任務。本文詳細講解了Go語言中的函數(shù),對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-07-07
  • GO 反射對性能的影響分析

    GO 反射對性能的影響分析

    這篇文章主要為大家介紹了GO 反射對性能的影響分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-01-01
  • golang中bufio.SplitFunc的深入理解

    golang中bufio.SplitFunc的深入理解

    這篇文章主要給大家介紹了關于golang中bufio.SplitFunc的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用golang具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-10-10
  • 解決go echo后端處理跨域的兩種操作方式

    解決go echo后端處理跨域的兩種操作方式

    這篇文章主要介紹了解決go echo后端處理跨域的兩種操作方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Go語言壓縮和解壓縮tar.gz文件的方法

    Go語言壓縮和解壓縮tar.gz文件的方法

    這篇文章主要介紹了Go語言壓縮和解壓縮tar.gz文件的方法,實例分析了使用Go語言壓縮文件與解壓文件的技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-02-02
  • Golang如何將上傳的文件壓縮成zip(小案例)

    Golang如何將上傳的文件壓縮成zip(小案例)

    這篇文章主要介紹了Golang如何將上傳的文件壓縮成zip(小案例),這是一個簡單的golang壓縮文件小案例,可做很多的拓展,這里使用的庫是archive/zip,在gopkg里面搜zip就行,需要的朋友可以參考下
    2024-01-01
  • 使用Go語言實現(xiàn)遠程傳輸文件

    使用Go語言實現(xiàn)遠程傳輸文件

    本文主要介紹如何利用Go語言實現(xiàn)遠程傳輸文件的功能,有需要的小伙伴們可以參考學習。下面跟著小編一起來學習學習。
    2016-08-08
  • Golang中slice切片的實現(xiàn)示例

    Golang中slice切片的實現(xiàn)示例

    Go語言中,切片是對數(shù)組的抽象,提供了更靈活的動態(tài)數(shù)組解決方案,本文就來介紹一下Golang中slice切片的實現(xiàn)示例,感興趣的可以了解一下
    2024-09-09
  • 深入了解Golang官方container/list原理

    深入了解Golang官方container/list原理

    在?Golang?的標準庫?container?中,包含了幾種常見的數(shù)據(jù)結構的實現(xiàn),其實是非常好的學習材料,本文主要為大家介紹了container/list的原理與使用,感興趣的可以了解一下
    2023-08-08

最新評論