| // Copyright 2013 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package sort_test |
| |
| import ( |
| "fmt" |
| "sort" |
| ) |
| |
| // A couple of type definitions to make the units clear. |
| type earthMass float64 |
| type au float64 |
| |
| // A Planet defines the properties of a solar system object. |
| type Planet struct { |
| name string |
| mass earthMass |
| distance au |
| } |
| |
| // By is the type of a "less" function that defines the ordering of its Planet arguments. |
| type By func(p1, p2 *Planet) bool |
| |
| // Sort is a method on the function type, By, that sorts the argument slice according to the function. |
| func (by By) Sort(planets []Planet) { |
| ps := &planetSorter{ |
| planets: planets, |
| by: by, // The Sort method's receiver is the function (closure) that defines the sort order. |
| } |
| sort.Sort(ps) |
| } |
| |
| // planetSorter joins a By function and a slice of Planets to be sorted. |
| type planetSorter struct { |
| planets []Planet |
| by func(p1, p2 *Planet) bool // Closure used in the Less method. |
| } |
| |
| // Len is part of sort.Interface. |
| func (s *planetSorter) Len() int { |
| return len(s.planets) |
| } |
| |
| // Swap is part of sort.Interface. |
| func (s *planetSorter) Swap(i, j int) { |
| s.planets[i], s.planets[j] = s.planets[j], s.planets[i] |
| } |
| |
| // Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter. |
| func (s *planetSorter) Less(i, j int) bool { |
| return s.by(&s.planets[i], &s.planets[j]) |
| } |
| |
| var planets = []Planet{ |
| {"Mercury", 0.055, 0.4}, |
| {"Venus", 0.815, 0.7}, |
| {"Earth", 1.0, 1.0}, |
| {"Mars", 0.107, 1.5}, |
| } |
| |
| // ExampleSortKeys demonstrates a technique for sorting a struct type using programmable sort criteria. |
| func Example_sortKeys() { |
| // Closures that order the Planet structure. |
| name := func(p1, p2 *Planet) bool { |
| return p1.name < p2.name |
| } |
| mass := func(p1, p2 *Planet) bool { |
| return p1.mass < p2.mass |
| } |
| distance := func(p1, p2 *Planet) bool { |
| return p1.distance < p2.distance |
| } |
| decreasingDistance := func(p1, p2 *Planet) bool { |
| return !distance(p1, p2) |
| } |
| |
| // Sort the planets by the various criteria. |
| By(name).Sort(planets) |
| fmt.Println("By name:", planets) |
| |
| By(mass).Sort(planets) |
| fmt.Println("By mass:", planets) |
| |
| By(distance).Sort(planets) |
| fmt.Println("By distance:", planets) |
| |
| By(decreasingDistance).Sort(planets) |
| fmt.Println("By decreasing distance:", planets) |
| |
| // Output: By name: [{Earth 1 1} {Mars 0.107 1.5} {Mercury 0.055 0.4} {Venus 0.815 0.7}] |
| // By mass: [{Mercury 0.055 0.4} {Mars 0.107 1.5} {Venus 0.815 0.7} {Earth 1 1}] |
| // By distance: [{Mercury 0.055 0.4} {Venus 0.815 0.7} {Earth 1 1} {Mars 0.107 1.5}] |
| // By decreasing distance: [{Mars 0.107 1.5} {Earth 1 1} {Venus 0.815 0.7} {Mercury 0.055 0.4}] |
| } |