1. 程式人生 > 程式設計 >從插入排序來理解 Go 的介面

從插入排序來理解 Go 的介面

插入排序

根據插入排序的思想,我們很容易就可以完成插入排序的程式碼如下。

func insertionSort(data []int) {
    lo,hi := 0,len(data)
    for i := lo + 1; i < hi; i++ {
        for j := i; j > lo && data[j] < data[j-1]; j-- {
            data[j],data[j-1] = data[j-1],data[j]
        }
    }
}
複製程式碼

我們可以驗證一下,確實沒有問題。

package
main import ( "fmt" ) func main() { nums := []int{2,3,4,1,7,9,10,21,17} insertionSort(nums) fmt.Println(nums) } 複製程式碼

程式碼輸出為,結果正確

[1 2 3 4 7 9 10 17 21]
複製程式碼

問題

好,現在問題來了,都知道 Go 是靜態語言,那麼就意味著不同的資料型別可能導致上述的插入排序不可用。比如說,某天產品想要支援 uint32 的插入排序。嗯,很簡單,直接 Ctrl+c + Ctrl+c 稍微修改一下。

func insertionSortUint32
(data []uint32)
{ lo,data[j] } } } 複製程式碼

誰知道哪天產品腦子又抽風,他想要支援 float32 型別的插入排序,程式碼可能又得加幾行。

func insertionSortFloat32(data []float32) {
    lo,data[j]
        }
    }
}
複製程式碼

好像還看得下去,我們知道 Go 中的型別可不止這 3 種,再這麼被搞下去是不是要爆炸了?沒關係,我們有強大的 IDE 可以快速實現。???

2332

好了,開個玩笑。如果我們是提供一個庫的形式,使用者需要一個型別,我們就得加一個型別支援,這樣就沒法搞事了?

解決

首先,回到上訴的三個型別的排序中來,我們可以發現這幾個排序除了資料型別是基本一致的。如果我們想用一個函式來支援所有的資料型別,我們是不是隻能使用 interface來實現這個功能?但是 interface 又不支援運算操作,如果斷言出來,還是跟以前一樣麻煩。我們看看程式碼中需要對資料進行運算操作的地方。

發現排序中只有len(data)data[j] < data[j-1]data[j],data[j-1] = data[j-1],data[j]這三種操作 interface 不支援。如果我們讓 interface 實現這三個方法不就解決了我的問題了嗎?接下來我們通過這種思路修改一下我們的插入排序 。程式碼如下,

type Data interface {
    Len() int
    Less(i,j int) bool
    Swap(i,j int)
}

func insertionSort(data Data) {
    lo,data.Len()
    for i := lo + 1; i < hi; i++ {
        for j := i; j > lo && data.Less(j,j-1); j-- {
            data.Swap(j,j-1)
        }
    }
}
複製程式碼

我們使用了interface來替代寫死的資料型別。如果呼叫方使用,只要實現 Data 介面就行了。

package main

import (
    "fmt"
)

type Uint32Slice []uint32

func (u Uint32Slice) Len() int {return len(u)}
func (u Uint32Slice) Less(i,j int) bool {return u[i] < u[j]}
func (u Uint32Slice) Swap(i,j int) {u[i],u[j] = u[j],u[i]}

type Float32Slice []float32

func (u Float32Slice) Len() int {return len(u)}
func (u Float32Slice) Less(i,j int) bool {return u[i] < u[j]}
func (u Float32Slice) Swap(i,u[i]}


func main()  {
    nums := Uint32Slice{2,17}
    insertionSort(nums)
    fmt.Println(nums)

    float32Nums := Float32Slice{2,17}
    insertionSort(float32Nums)
    fmt.Println(float32Nums)
}
複製程式碼

可以驗證,結果沒有問題。

[1 2 3 4 7 9 10 21 17]
[1 2 3 4 7 9 10 21 17]
複製程式碼

總結

我們通過介面實現了一個支援多種資料型別的插入排序,呼叫者只需要實現 Data 這個介面就可以使用了,而不用去修改插入排序原有的函式定義。這樣使得我們的程式碼抽象度更高也更靈活,當我們面臨類似的需求時,介面就是答案。