iT邦幫忙

2023 iThome 鐵人賽

DAY 19
0
Modern Web

起步Go!Let's Go!系列 第 19

[ Day19 ] Go 介面實作:編織功能的契約

  • 分享至 

  • xImage
  •  

接續上一篇,究竟甚麼後需要使用到 Interface 呢?
這裡不得不提 Go 的設計哲學之一,「基於介面而非實作」(Interface-based rather than implementation-based),這意味著許多內置的功能都需要開發者先實作特定的介面才能使用。
舉例來說,像是 fmt 包中的 Stringer 介面,開發者需要實作該介面中的 String() 方法才能讓該物件能夠以某種格式印出,否則 fmt.Print 等函式會使用該物件的預設輸出,通常是類似 "{main.Person}" 這樣的字串。
另外,像是 database/sql 包中的 Driver 介面,開發者需要實作該介面中的 OpenClose 方法,才能將自己的資料庫驅動程式納入 sql 包的生態系統,方便其他開發者使用。

這一章以 Go 提供的一個排序套件,但有些相關的參數是要自己決定的,例如,長度、大小以及要怎麼把兩個交換要排序的元素。
生活上的例子,今天請廠商做衣服,必須先提供你要的圖案給廠商,廠商才能開啟產線。

要使用 sort 的功能,要先將它(sort) import 引入進來:

import (
    "fmt"
    "sort"
)

STEP1 先確認要使用的函式

我們可以先參考 Golang 的官方文件:sort
這次我們確定要使用 sort.Sort() 函式,但是裡頭的參數是 sort.Interface 型態。

看完官方解釋後,它大概的意思

Sort 會排序 data。它會呼叫 data.Len 來決定 n,並呼叫 data.Lessdata.Swap O(n*log(n)) 次,這個排序為不穩定排序。

STEP2 尋找如何實作 Interface

要使用 sort.Sort() 前必需先實作 sort.Interface
點我!!! Interface

type Interface interface{
    // Len is the number of elements in the collection.
    Len() int
    // Less reports whether the element with index i should sort before the element with index j.
    Less(i, j int) bool
    // Swap swaps the elements with indexes i and j.
    Swap(i, j int)
}

解釋:
Len(): 要排序的陣列總數。
Less(i, j int) bool: 如果第 i 個元素要在第 j 個元素前面回傳 true,不然回傳 false
Swap(i, j int): 定義如果要把第 i 個元素和第 j 個元素交換。

語法補充:

  1. Less(i, j int)Less(i int, j int) 意思相同,前者是一種簡寫。
  2. 使用引入的套件前面要加入套件的名稱,比如引入 sort 時若要使用 sort 裡的函式、常數、型態,必需在這些東西前方加上 sort. 。比如 sort.Sort(), sort.Interface, fmt.Println()
  3. 如果引用的套件是 encoding/json 這時套件名稱為 json,總之就是挑「最後的那一個字串」。如果有兩個重複的套件名稱呢?比如 foo/aaa, bar/aaa,這時只要加上別稱就行了。
imoprt(
   a "foo/aaa"
   b "bar/aaa"
)

func main(){
   a.F()
   b.F()
}

STEP3 排序一個 int slice

由小到大排序:

list := []int{1, 4, 8, 3, 5, 7, 9, 6}

STEP4 實作

因為我們無法對 []int 添加方法,所以要試著使用自己的型態,所以在這邊可以自訂一個型態:

package main
import (
    "fmt"
    "sort"
)
type myList []int

func main(){
    list := []int{1, 4, 8, 3, 5, 7, 9, 6}
    newList := myList(list)  // 轉型變成自訂型態
    fmt.Println(newList)
    sort.Sort(newList)
    fmt.Println(newList)
}

接著,對自訂義的型態新增三個方法,來滿足 sort.Interface:

package main
import (
    "fmt"
    "sort"
)
type myList []int

func (list myList) Len() int{
    return len(list)
}
func (list myList) Less(i, j int) bool{
    return list[i] < list[j]
}
func (list myList) Swap(i, j int){
    list[i], list[j] = list[j], list[i]
    // 因為 Go 允許多對多賦值所以可以一行完成,所以就不用使用傳統的交換方法。
}

func main(){
    list := []int{1, 4, 8, 3, 5, 7, 9, 6}
    newList := myList(list)  // 轉型變成自訂型態
    fmt.Println(newList)
    sort.Sort(newList)
    fmt.Println(newList)
}

執行結果:
[1 4 8 3 5 7 9 6]
[1 3 4 5 6 7 8 9]

如果我要從大到小排序呢?

這時只需要更改 Less() 就行。

func (list myList) Less(i, j int) bool{
    return list[j] < list[i]
}

上一篇
[ Day 18 ] Go 介面 (Interface):程式碼的通用魔法
下一篇
[ Day 20 ] Go 反射:程式碼的魔法鏡
系列文
起步Go!Let's Go!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言