深入 Go interface: Duck Typing 和多態

Duck Typing

鴨子類型(Duck Typing)是一種編程概念,關鍵在於根據對象的行爲來確定其類型。

通常的解釋是通過一個巧妙的例子:根據對象的行爲來判斷它是否是一隻鴨子。如果它游泳像鴨子、嘎嘎叫像鴨子,那麼它就可以被認爲是一隻鴨子。

動態語言如 Python 和 JavaScript 自然支持這種特性,但與靜態語言相比,動態語言缺乏重要的類型檢查。

Go 語言的接口設計與鴨子類型概念密切相關,但與動態語言不同。在 Go 中,類型檢查發生在編譯時。

理解 Go Interfaces

Go 的接口就像一組方法,充當抽象類型。它們創建了一種隱形的約定,允許任何符合接口中所定義方法的類型被識別爲該類型的一部分。

例如,假設我們定義一個鴨子接口,如下所示:

type Duck interface {
 Quack()   // Duck quacks
 DuckGo()  // Duck moves
}

現在,讓我們創建一個雞(Chicken)類型:

type Chicken struct {
}

func (c Chicken) IsChicken() bool {
 fmt.Println("I am a chicken")
}

這隻雞很特別,能夠執行類似鴨子的動作:

func (c Chicken) Quack() {
 fmt.Println("Quack")
}

func (c Chicken) DuckGo() {
 fmt.Println("Strutting along")
}

請注意,我們僅實現了 Duck 接口的方法,而沒有顯式地將雞的類型與 Duck 接口綁定。

讓我們創建一個執行鴨子可以做的動作的函數:

func DoDuck(d Duck) {
 d.Quack()
 d.DuckGo()
}

由於雞實現了鴨子的所有方法,因此它也被視爲一隻鴨子。因此,在主函數中,我們可以這樣做

func main() {
 c := Chicken{}
 DoDuck(c)
}

順利運行。這不就是在其他語言中實現多態性嗎?這就是 Go 實現多態性的方式。

Empty Interface

現在,讓我們談談空接口。

一個沒有定義任何方法的接口,表示爲 interface{},意味着任何類型都可以滿足它。這就是爲什麼當函數參數類型是 interface{} 時,它可以接受任何類型的參數。

例如:

package main

import "fmt"
func main() {
        var i interface{} = 2
        fmt.Println(i)
}

在更常見的情況下,Go 中的 interface{} 通常用作函數參數,以模擬其他語言中找到的泛型效果 (在支持泛型後這一用法被替代不少)。

Conclusion

總的來說,理解 Go 的接口這一概念非常重要。一旦掌握,理解其他 Go 概念,如類型、多態性、空接口、反射、類型檢查和斷言,就會變得更容易。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/d8zlxo_RLOZM3lAIhLDlmA