接續上一篇,究竟甚麼後需要使用到 Interface 呢?
這裡不得不提 Go 的設計哲學之一,「基於介面而非實作」(Interface-based rather than implementation-based),這意味著許多內置的功能都需要開發者先實作特定的介面才能使用。
舉例來說,像是 fmt 包中的 Stringer 介面,開發者需要實作該介面中的 String() 方法才能讓該物件能夠以某種格式印出,否則 fmt.Print 等函式會使用該物件的預設輸出,通常是類似 "{main.Person}" 這樣的字串。
另外,像是 database/sql 包中的 Driver 介面,開發者需要實作該介面中的 Open 和 Close 方法,才能將自己的資料庫驅動程式納入 sql 包的生態系統,方便其他開發者使用。
這一章以 Go 提供的一個排序套件,但有些相關的參數是要自己決定的,例如,長度、大小以及要怎麼把兩個交換要排序的元素。
生活上的例子,今天請廠商做衣服,必須先提供你要的圖案給廠商,廠商才能開啟產線。
要使用 sort 的功能,要先將它(sort) import 引入進來:
import (
"fmt"
"sort"
)
我們可以先參考 Golang 的官方文件:sort
這次我們確定要使用 sort.Sort() 函式,但是裡頭的參數是 sort.Interface 型態。
看完官方解釋後,它大概的意思
Sort會排序data。它會呼叫data.Len來決定n,並呼叫data.Less和data.SwapO(n*log(n))次,這個排序為不穩定排序。
要使用 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 個元素交換。
Less(i, j int) 與 Less(i int, j int) 意思相同,前者是一種簡寫。sort 時若要使用 sort 裡的函式、常數、型態,必需在這些東西前方加上 sort. 。比如 sort.Sort(), sort.Interface, fmt.Println()。encoding/json 這時套件名稱為 json,總之就是挑「最後的那一個字串」。如果有兩個重複的套件名稱呢?比如 foo/aaa, bar/aaa,這時只要加上別稱就行了。imoprt(
a "foo/aaa"
b "bar/aaa"
)
func main(){
a.F()
b.F()
}
由小到大排序:
list := []int{1, 4, 8, 3, 5, 7, 9, 6}
因為我們無法對 []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]
}