Golang學習摘錄六:介面

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

Go中關鍵字interface被賦予了很多不同的含義。每個類型都有介面,意味著對那個類型定義了方法集合。

// 這段代碼定義了具有一個欄位和兩個方法的結構類型s。type S struct { i int }func (p *S) Get() int { return p.i }func (p *S) Put(v int) { p.i = v }// 定義介面type I interface {  Get() int  Put(int)}// 對於介面I,S是合法的實現,因為它定義了 I 所需的兩個方法。注意:即便是沒有明 確定義 S 實現了 I,這也是正確的。// Go 程式的特性介面值:func f(p I) {// 定義一個函數接受一個介面類型作為參數  fmt.Println(p.Get()) // p實現了介面I,必須有Get()方法  p.Put(1) // Put()方法是類似的  // 這裡的變數p儲存了介面類型的值。 }// 調用var s Sf(&s) // 因為S實現了I,可以調用f向其傳遞S類型的值的指標// 擷取 s 的地址,而不是 S 的值的原因,是因為在 s 的指標上定義了方法,參閱上面的 代碼 5.1。這並不是必須的——可以定義讓方法接受值——但是這樣的話 Put 方法就不 會像期望的那樣工作了。// 定義另外一個類型同樣實現介面I:type R struct { i int }func (p *R) Get() int { return p.i } func (p *R) Put(v int) { p.i=v }// 函數f現在可以接受類型為R或S的變數。// 假設需要在函數f中知道實際的類型。在Go中可以使用type switch得到。func f(p I) {  switch t : p.(type) { // 類型判斷;在switch語句中使用(type)。檔案類型到變數t中。在switch之外使用(type)是非法的。    case *S:    case *R:    case S:    case R:    defaut:  }}// 類型判斷不是唯一的運行時得到類型的方法。 為了在運行時得到類型,同樣可以使用 “comma, ok” 來判斷一個介面類型是否實現了 某個特定介面:    if t, ok := p.(*S); ok {        fmt.Printf("%d\n", t.Get())    }// 確定一個變數實現了某個介面,可以使用:t := p.(*S)

空介面

interface{} // 每個類型都能匹配到空介面func g(something interface{}) int { // 用空介面作為參數的函數  return something.(I).Get() // 值 something 具有 類型 interface{},這意味著方法沒有任何約束:它能包含任何類型。.(I) 是 類型 斷言,用於轉換 something 到 I 類型的介面。// 如果有這個類型,則可以調用 Get() 函 數。因此,如果建立一個 *S 類型的新變數,也可以調用 g(),因為 *S 同樣實現了空 介面。}s = new(S)fmt.Println(g(s)) // 列印0// 如果調用g()的參數沒有實現I,會在運行時得到警告,如i:=5 fmt.Println(g(i)) // 在運行時警告:panic: interface conversion: int is not main.I: missing method Get,這是沒有問題的,因為內建類型int沒有Get()方法。

方法

方法就是有接受者的函數,可以在任意類型上定義方法(除了非本地類型,包括內建類型:int類型不能有方法)。但是可以建立一個擁有方法的整數類型。

type Foo intfunc (f Foo) Emit(){  fmt.Printf("%v",f)}type Emitter interface{  Emit()}func (i int) Emit() {....}  // 不能直接擴充內建類型func (a *net.AddrError) Emit(){...}// 不能直接擴充非本地類型// 可以通過建立類型的方式處理type newError net.AddrErrorfunc (a *newError) Emit(){...}// 

介面定義為一個方法的集合。方法包含實際的代碼。換句話說,一個介面就是定義,而方法就是實現。因此,接受者不定定義為介面類型,這樣做會引起invalid receiver type編譯錯誤

接收者類型必須是 T 或 *T,這裡的 T 是類型名。T 叫做接收者基礎類型或 簡稱基礎類型。基礎類型一定不能使指標或介面類型,並且定義在與方法 相同的包中。

在Go中建立指向介面的指標是無意義的。實際上建立介面值的指標也是非法的。

介面名字

根據規則,單方法介面命名為方法名加上 -er 尾碼:Reader,Writer,Formatter 等。
有一堆這樣的命名,高效的反映了它們職責和包含的函數名。Read,Write,Close, Flush,String 等等有著規範的聲明和含義。為了避免混淆,除非有類似的聲明和含 義,否則不要讓方法與這些重名。相反的,如果類型實現了與眾所周知的類型相同的方 法,那麼就用相同的名字和聲明;將字串轉換方法命名為 String 而不是 ToString。
冒泡排序整型資料

func bubblesort(n []int) {  for i:=0; i< len(n)-1; i++ {      for j:=i+1; j< len(n); j++ {         if n[j]<n[i] {            n[i], n[j] = n[j], n[i]        }     }  }}

類似的排序字串
func bubblesortString(n []string){ / .... / }
基於此,可能需要兩個函數,每個類型一個。而通過使用介面可以讓這個變得更加通用。
下面的方法不能用

func sort(i []interface{}) { // 函數將接受一個空介面的slice  switch i.(type) {// 使用type switch找到輸入參數實際的類型    case string: // 排序        // ....    case int:        // ...  }  return /*....*/    //返回排序後的slice}

但是如果用sort([]int{1,4,5})調用這個函數,會失敗:cannot use i (type []int) as type []interface in function argment
這是因為Go不能(隱式)轉換為slice。
所以需要通過介面的方式建立Go形式的“通用”函數。
步驟:
1.定義一個有著若干排序相關方法的介面函數(這裡叫做Sorter)。至少需要擷取slice長度的函數,比較兩個值的函數和交換函數;

type Sorter interface {  Len() int // len()作為方法  Less(i,j int) bool // p[j]<p[i]作為方法  Swap(i,j int)  // p[i],p[i] = p[j],p[i]作為方法}

2.定義用於排序slice的新類型。注意定義的是slice類型;

type Xi []inttype Xs []string

3.實現Sorter介面的方法。

//整數為:func (p Xi) Len() int { return len(p) }func (p Xi) Less(i int, j int) bool { return p[j]<p[i] }func (p Xi) Swap(i int, j int) { p[i],p[j]=p[j],p[i] }// 字串的:func (p Xs) Len() int { return len(p) } func (p Xs) Less(i int, j int) bool { return p[j] < p[i] } func (p Xs) Swap(i int, j int) { p[i], p[j] = p[j], p[i]

4.編寫作用於Sorter介面的通用排序函數。

func Sort(x Sorter) {// x現在是Sorter類型;   for i:=0; i<x.Len()-1; i++ {    for j:=i+1; j<x.Len(); j++ {       if x.Less(i, j) {          x.Swap(i, j)       }    }  }}// 現在可以像下面這樣使用通用的 Sort 函數:ints := Xi{44, 67, 3, 17, 89, 10, 73, 9, 14, 8}strings := Xs{"nut", "ape", "elephant", "zoo", "go"}Sort(ints)fmt.Printf("%v\n", ints)Sort(strings)fmt.Printf("%v\n", strings)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.