1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package sort_test 6 7 import ( 8 "fmt" 9 "sort" 10 ) 11 12 // A couple of type definitions to make the units clear. 13 type earthMass float64 14 type au float64 15 16 // A Planet defines the properties of a solar system object. 17 type Planet struct { 18 name string 19 mass earthMass 20 distance au 21 } 22 23 // By is the type of a "less" function that defines the ordering of its Planet arguments. 24 type By func(p1, p2 *Planet) bool 25 26 // Sort is a method on the function type, By, that sorts the argument slice according to the function. 27 func (by By) Sort(planets []Planet) { 28 ps := &planetSorter{ 29 planets: planets, 30 by: by, // The Sort method's receiver is the function (closure) that defines the sort order. 31 } 32 sort.Sort(ps) 33 } 34 35 // planetSorter joins a By function and a slice of Planets to be sorted. 36 type planetSorter struct { 37 planets []Planet 38 by func(p1, p2 *Planet) bool // Closure used in the Less method. 39 } 40 41 // Len is part of sort.Interface. 42 func (s *planetSorter) Len() int { 43 return len(s.planets) 44 } 45 46 // Swap is part of sort.Interface. 47 func (s *planetSorter) Swap(i, j int) { 48 s.planets[i], s.planets[j] = s.planets[j], s.planets[i] 49 } 50 51 // Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter. 52 func (s *planetSorter) Less(i, j int) bool { 53 return s.by(&s.planets[i], &s.planets[j]) 54 } 55 56 var planets = []Planet{ 57 {"Mercury", 0.055, 0.4}, 58 {"Venus", 0.815, 0.7}, 59 {"Earth", 1.0, 1.0}, 60 {"Mars", 0.107, 1.5}, 61 } 62 63 // ExampleSortKeys demonstrates a technique for sorting a struct type using programmable sort criteria. 64 func Example_sortKeys() { 65 // Closures that order the Planet structure. 66 name := func(p1, p2 *Planet) bool { 67 return p1.name < p2.name 68 } 69 mass := func(p1, p2 *Planet) bool { 70 return p1.mass < p2.mass 71 } 72 distance := func(p1, p2 *Planet) bool { 73 return p1.distance < p2.distance 74 } 75 decreasingDistance := func(p1, p2 *Planet) bool { 76 return distance(p2, p1) 77 } 78 79 // Sort the planets by the various criteria. 80 By(name).Sort(planets) 81 fmt.Println("By name:", planets) 82 83 By(mass).Sort(planets) 84 fmt.Println("By mass:", planets) 85 86 By(distance).Sort(planets) 87 fmt.Println("By distance:", planets) 88 89 By(decreasingDistance).Sort(planets) 90 fmt.Println("By decreasing distance:", planets) 91 92 // Output: By name: [{Earth 1 1} {Mars 0.107 1.5} {Mercury 0.055 0.4} {Venus 0.815 0.7}] 93 // By mass: [{Mercury 0.055 0.4} {Mars 0.107 1.5} {Venus 0.815 0.7} {Earth 1 1}] 94 // By distance: [{Mercury 0.055 0.4} {Venus 0.815 0.7} {Earth 1 1} {Mars 0.107 1.5}] 95 // By decreasing distance: [{Mars 0.107 1.5} {Earth 1 1} {Venus 0.815 0.7} {Mercury 0.055 0.4}] 96 } 97