日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【14】GO语言的接口类型

發(fā)布時間:2024/1/17 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【14】GO语言的接口类型 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
原創(chuàng)作品,允許轉(zhuǎn)載,轉(zhuǎn)載時請務(wù)必以超鏈接形式標(biāo)明文章?原始出處?、作者信息和本聲明。否則將追究法律責(zé)任。http://qingkechina.blog.51cto.com/5552198/1675115

1、什么是接口?

在面向?qū)ο蟮恼Z言中,接口用來限制實現(xiàn)類行為的。怎么理解這句話呢?


定義一個Person接口,我只會站在我的角度上考慮問題,比如Person(人),自然想到會吃飯、睡覺等:

interface Person

{

? ? ??// 人會吃飯

? ? ? void eat();


? ? ??// 人會睡覺

? ? ? void sleep();

}


我是站在接口角度上考慮接口如何定義,此時不會過多考慮實現(xiàn)類的行為。

這很正常,因為我不能確定誰會使用我的接口,有一天SuperMan說:“我要用你定義的接口”,那SuperMan必須用implements實現(xiàn)Person接口的行為:

// SuperMan實現(xiàn)Person接口

public class SuperMan?implements?Person

{

? ? ??// 超人會吃飯

? ? ? ?public void eat()

? ? ? ?{

? ? ? ? ? ? ? System.out.println("super man can eat.");

? ? ? ?}


? ? ? ?// 超人會睡覺

? ? ? ?public void sleep()

? ? ? ?{

? ? ? ? ? ? ? System.out.println("super man can sleep.");

? ? ? ?}

}


等到SuperMan實現(xiàn)完了之后,他對我說:“作為超人,我是會飛的哦~”

這時作為Person定義者的我,只有兩個選擇:

  • 對SuperMan說:“飛是你自己的行為,我不幫你定義這種行為!”。可是經(jīng)過若干萬年之后人類進(jìn)化了怎么辦?

  • 對SuperMan說:“好吧,我?guī)湍愣x這種行為,可是一旦Person有了fly,你也必須實現(xiàn)fly”

其實無論上面哪種結(jié)果,都相當(dāng)于接口把實現(xiàn)類綁架了。


【備注】:悄悄地告訴你,上面的代碼是Java語言 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?



2、GO語言的接口呢?

GO語言有接口類型interface{}),它與面向?qū)ο蟮慕涌诤x不同,GO語言的接口類型與數(shù)組(array)、切片(slice)、集合(map)、結(jié)構(gòu)體(struct)是同等地位的。怎么理解這句話呢?

我們前面已知道:

var num int ?// 定義了一個int型變量num

同理:

var any interface{}?// 定義了一個接口類型變量any

從這個角度上看,GO的interface{}與面向?qū)ο蟮慕涌谑遣灰粯影伞???更加不一樣的是,interface{}是一個任意類型,或者說是萬能類型。


3、GO語言的任意類型

也就是說定義一個變量為interface{}類型,可以把任意的值賦給這個變量,例如:

var v1 interface{} = 250 ? ? ??// 把int值賦給interface{}

var v2 interface{} = "eagle"?// 把string值賦給interface{}

var v3 interface{} = &v1 ? ? ?// 把v1的地址賦給interface{}

當(dāng)然函數(shù)的入?yún)㈩愋鸵部梢允莍nterface{},這樣函數(shù)就可以接受任意類型的參數(shù),例如GO語言標(biāo)準(zhǔn)庫fmt中的函數(shù)Println()

func Println(args ...interface{}){

? ? ? ??// 略

}


任意類型看起來很爽,可以把任意的值都賦給interface{}類型變量,就像JDK1.4時的Vector,那時候Java還沒有泛型的概念,任意值都可以向Vector里面放,但問題也接踵而至:

// 定義一個長度為3的Any類型數(shù)組,求數(shù)組元素之和,即anyArr[0]+anyArr[1]+anyArr[2]

var anyArr [3]interface{}

anyArr[0] = "eagle" ? ?// anyArr[0]賦值為字符串

anyArr[1] = 20 ? ? ? ? ??// anyArr[1]賦值為int

anyArr[2] = 75.3 ? ? ???// anyArr[2]賦值為float64

// 此時若求和,會有什么結(jié)果呢?

fmt.Println(anyArr[0] + anyArr[1] + anyArr[2])


4、類型判斷

上例直觀上來看,string不能和int直接相加,所以我們需要判斷元素類型,若元素類型是數(shù)字型的,我們就執(zhí)行“+”操作;若元素類型是字符串型的,我們就跳過。這里需要引入另外一個知識:switch-type

即:拿到一個interface{}之后,可以結(jié)合switch語句判斷變量的類型 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

例如:

var v interface{} = 3

switch?v.(type){

? ? ? case int:

? ? ? ? ? ? ? fmt.Println("3 is int")

? ? ? case string:

? ? ? ? ? ? ? fmt.Println("3 is string")

? ? ? default:

? ? ? ? ? ? ? fmt.Println("unkown type")

}

所以上面的例子可以進(jìn)一步修改如下:

// 定義一個長度為3的Any類型數(shù)組,求數(shù)組元素之和,即anyArr[0]+anyArr[1]+anyArr[2]

var anyArr [3]interface{}

anyArr[0] = "eagle"

anyArr[1] = 20

anyArr[2] = 75.3


// 定義一個總和變量total

var total float64 = 0


// 遍歷Any類型數(shù)組

for i := 0; i < len(anyArr); i++ {

? ? ? ??// 針對Any類型數(shù)組中的每個元素進(jìn)行類型查詢

? ? ? ??switch?vType := anyArr[i].(type)?{

? ? ? ? ? ? ? case?int:

? ? ? ? ? ? ? ? ? ? ? total += float64(vType)

? ? ? ? ? ? ? case?float64:

? ? ? ? ? ? ? ? ? ? ? total += vType

? ? ? ? ? ? ? default:

? ? ? ? ? ? ? ? ? ? ? // do nothing

? ? ? ? }

}


// 打印Any類型數(shù)組中數(shù)字之和

fmt.Println(total)


5、interface類型與struct類型

?從上面看interface類型很簡單嘛,或許吧。

我們再回顧一下struct類型,struct類型是一個結(jié)構(gòu)體,里面可以定義成員,它類似面向?qū)ο蟮囊粋€類,類里面可以定義成員變量,比如:

// 定義一個person結(jié)構(gòu)體,里面有姓名、年齡、身高、體重成員

type person struct{

? ? ? ? name ? ? ? ? ? ? ? ? string

? ? ? ? age ? ? ? ? ? ? ? ? ? ?int

? ? ? ? height, weight ? float64

}

那么interface類型是否也可以這樣定義呢?如下:

/**

?* 定義一個手表接口,通過手表接口我們可以知道小時、分鐘和秒

?*/

type watch interface {

? ? ? ? getHour() int

? ? ? ? getMinute() int

? ? ? ? getSecond() int

}

通過編譯(go build myIf.go)會發(fā)現(xiàn)并沒有拋出錯誤!

從結(jié)果可以看出完全可以這樣定義一個類型為interface的變量watch,并且還可以為watch增加相應(yīng)的方法;但與struct不同的是:struct里面的成員是變量,而interface里面的成員是函數(shù),即我們可以使用interface定義接口。


6、interface定義接口示例

(1)GO語言接口實現(xiàn)

? ? ? ?周圍的不少朋友現(xiàn)在都有一款iWatch智能手表,一般都用來運(yùn)動時監(jiān)控心率,這也意味著iWatch不僅能看時間這么簡單。下面我們定義一個iWatch類型:

type iWatch int ? ?// 定義一個iWatch類型,它實際上就是int型;相當(dāng)于為int型取一個別名iWatch

接下來為iWatch類型增加三個方法,分別為getHour()、getMinute()、getSecond()

// 為iWatch增加getHour()方法

func (w iWatch) getHour() int {

? ? ? ? return time.Now().Hour()

}


// 為iWatch增加getMinute()方法

func (w iWatch) getMinute() int {

? ? ? ? return time.Now().Minute()

}


// 為iWatch增加getSecond()方法

func (w iWatch) getSecond() int {

? ? ? ? return time.Now().Second()

}

下面是GO語言的精彩內(nèi)容,請各位看客睜大眼睛:

func main() {

? ? ? ? var w watch ?// 定義類型為watch的變量w

? ? ? ? var t iWatch ?// 定義類型為iWatch的變量t

? ? ? ? w = t ? ? ? ? ? ??// 把類型為watch的變量w賦值給類型為iWatch的變量t,這樣能行的通嗎?

? ? ? ? fmt.Println("Current Hour:", w.getHour(), ", Minute:", w.getMinute(), ", Second:", w.getSecond())

}

在這個測試代碼中:

var w watch

相當(dāng)于定義了一個接口變量

var t iWatch

相當(dāng)于定義了一個iWatch對象

w = t

直接把對象t 賦給了接口變量w,但沒有像其它面向?qū)ο笳Z言那樣,讓iWatch?implements?watch,這樣能行的通嗎?

把“嗎”字去掉,請看結(jié)果:

神奇吧 :)

以上是GO語言的接口實現(xiàn)。


(2)Java語言的接口實現(xiàn)

用面向?qū)ο蟮木幊陶Z言來解釋:

在面向?qū)ο蟮木幊陶Z言中,比如Son是一個實現(xiàn)類,Father是一個接口,Son要實現(xiàn)Father接口,必須使用implements顯式地聲明,同時在Son中實現(xiàn)Father里面定義的方法,比如:

interface Father{

? ? ? ? ?getHour();

}


class Son?implements?Father{

? ? ? ? ?// 實現(xiàn)父接口Father定義的方法getHour()

? ? ? ? ?public int getHour(){

? ? ? ? ? ? ? ? ?return 20;

? ? ? ? ?} ? ? ?

}

一旦接口Father增加一個方法getSecond(),那么實現(xiàn)該接口的所有孩兒都必須實現(xiàn)getSecond()方法。在使用時:

Father father = new Son();

即孩兒對象可以賦值給Father接口


【備注】:若對上面面向?qū)ο缶幊陶Z言不熟悉的話,建議看一下設(shè)計模式相關(guān)的書籍



(3)侵入式接口和非侵入式接口

像上面(2)中的Java就是侵入式接口。

GO語言中,像上面(1)所示,盡管定義了接口watch,但實現(xiàn)類iWatch并沒有顯示地聲明實現(xiàn)該接口,只是watch中的方法都已在iWatch中實現(xiàn),那么這種父子關(guān)系已建立,這種接口被稱為“非侵入式接口”


7、引申

上面例子中,為iWatch定義了三個方法,現(xiàn)在我們修改一下這三個方法:

// 為*iWatch增加getHour()方法

func (w *iWatch) getHour() int {

? ? ? ? return time.Now().Hour()

}


// 為*iWatch增加getMinute()方法

func (w *iWatch) getMinute() int {

? ? ? ? return time.Now().Minute()

}


// 為*iWatch增加getSecond()方法

func (w *iWatch) getSecond() int {

? ? ? ? return time.Now().Second()

}

這相當(dāng)于并不是為iWatch類型增加了三個方法,而是為*iWatch類型增加了三個方法,那么調(diào)用時也需要相應(yīng)修改:

func main() {

? ? ? ? var w watch

? ? ? ? var t iWatch

? ? ? ? w = &t ? ??? ?

? ? ? ? fmt.Println("Current Hour:", w.getHour(), ", Minute:", w.getMinute(), ", Second:", w.getSecond())

}


好了,關(guān)于GO語言的接口類型就聊到這里,請記住這么三句話:

  • interface是類型

  • interface類型的變量可以賦值

  • 任何實現(xiàn)了interface類型的具體類型變量,都可以賦值給interface類型的變量

本文出自 “青客” 博客,請務(wù)必保留此出處http://qingkechina.blog.51cto.com/5552198/1675115

總結(jié)

以上是生活随笔為你收集整理的【14】GO语言的接口类型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。