github.com/AESNooper/go/src@v0.0.0-20220218095104-b56a4ab1bbbb/sort/example_keys_test.go (about)

     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  }