sort.Reverseの実装 〜コンポジションの活用〜
golangでソートを行うsortパッケージは、sort.Interfaceを満たすメソッドが定義されていればソートできるようになっている。 code:sort
(*'-') < go doc -src sort.Interface
// A type, typically a collection, that satisfies sort.Interface can be
// sorted by the routines in this package. The methods require that the
// elements of the collection be enumerated by an integer index.
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)
}
例えばStringの配列のソートをしたかったら、こんな感じで使う。
code:string_sort.go
import (
"fmt"
"sort"
)
type StringSort []string
func (ss StringSort) Len() int {
return len(ss)
}
func (ss StringSort) Less(i, j int) bool {
}
func (ss StringSort) Swap(i, j int) {
}
func main() {
animals := []string{"elephant", "monkey", "dog", "cat"}
sort.Sort(StringSort(animals))
fmt.Println(animals)
インタフェースを満たしていれば、そのインタフェースに変換して渡せるのがいいところ。
これをReverseしたかったら、こうする。
code:string_sort.go
sort.Sort(sort.Reverse(StringSort(animals)))
fmt.Println(animals)
}
どうやって実装しているのだろう? go docに-uをつけるとexportされていないものも見ることができる。
code:sort_reverse.bash
(*'-') < go doc -src -u -all sort.reverse
// Reverse returns the reverse order for data.
func Reverse(data Interface) Interface {
return &reverse{data}
}
type reverse struct {
// This embedded Interface permits Reverse to use the methods of
// another Interface implementation.
Interface
}
// Less returns the opposite of the embedded implementation's Less method.
func (r reverse) Less(i, j int) bool {
return r.Interface.Less(j, i)
}
type reverse で Interface が書いてあるのがミソだと思う。これで sort.Interface のメソッドを引き継げる。reverseにはLess(i, j int) boolだけを定義しておいて、その他は他から引き継いでくる。イメージ図としてはこんな感じになる。
https://gyazo.com/93efaf87e747b748cd2a2b2be3c66bd8
Rubyのダック・タイピングに近い気もする。メソッドがあればそれでいいよという感じが。もう少し硬い感じだけど。Interface, Type, コンポジションをうまく活用するのがGoを楽しむ秘訣かなと思う。