接續上一篇,究竟甚麼後需要使用到 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.Swap
O(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]
}