Skip to Content
Course content

89: Sorting Custom Types with sort.Interface

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Up until now, we've probably been using sort.Ints or sort.Strings. Those are great for primitives, but in a real production codebase, you're rarely sorting just a list of integers. You're sorting users by their last login date, products by price, or—in the case we're looking at today—servers by their current CPU load.

To sort a custom collection, Go provides the sort.Interface. It's a bit old-school compared to some newer generic functions, but it's the foundation of how sorting works in Go. To satisfy this interface, your type needs three methods: Len(), Less(), and Swap().

Defining the Server collection

Let's imagine we're building a basic monitoring tool. We have a Server struct, and we want to sort a list of them so the most stressed server appears at the top. First, we define our data.

type Server struct {
    Name string
    Load float64
}

// I'm creating a named type for the slice here. 
// This is the part most people forget: you can't attach methods to 
// a raw slice like []Server. You need a defined type.
type ServerList []Server

Implementing the sort.Interface contract

Now we have to tell Go how to handle ServerList. The sort package doesn't know what a "Server" is or how to compare "Load"; it just knows how to call these three specific methods.

func (s ServerList) Len() int {
    return len(s)
}

func (s ServerList) Swap(i, j int) {
    s[i], s[j] = s[j], s[i]
}

func (s ServerList) Less(i, j int) bool {
    return s[i].Load < s[j].Load
}

At this point, ServerList implicitly implements sort.Interface. We can now pass it directly into sort.Sort().

Correcting the sorting direction

I just ran a quick test with this code, and I realized I made a classic mistake. Because I used s[i].Load < s[j].Load in my Less method, sort.Sort() gave me the servers in ascending order. The server with the lowest load is at the top. That's the opposite of what a monitoring dashboard needs; I want the "hottest" server first.

The trick here is that Less doesn't literally have to mean "less than" in a mathematical sense—it just defines which element should come first. To get a descending sort, I just need to flip the comparison operator.

func (s ServerList) Less(i, j int) bool {
    // Flipping this to > ensures the higher load comes first
    return s[i].Load > s[j].Load
}

Putting it all together

Now that the logic is corrected, we can actually use it. I'll initialize a few servers and call the sort function. Notice how sort.Sort takes the interface, not the slice itself, though since ServerList is a slice, it works seamlessly.

func main() {
    servers := ServerList{
        {"web-prod-01", 0.45},
        {"web-prod-02", 0.92},
        {"db-master", 0.78},
        {"cache-01", 0.12},
    }

    sort.Sort(servers)

    for _, s := range servers {
        fmt.Printf("%s: %.2f\n", s.Name, s.Load)
    }
}
// Output:
// web-prod-02: 0.92
// db-master: 0.78
// web-prod-01: 0.45
// cache-01: 0.12

It's a bit of boilerplate—writing Len, Less, and Swap every time feels tedious—but it's incredibly performant because it avoids the overhead of reflection or frequent interface casting during the sort loop.




📋 Practical Task

Build a High-Value Customer Sorter

You are tasked with creating a reporting tool for a sales team. They need to sort a list of customers based on their total spend, from highest to lowest (descending).

Requirements:

  • Create a Customer struct with Name (string) and TotalSpend (float64).
  • Define a custom slice type CustomerList.
  • Implement the sort.Interface (Len, Less, and Swap) for CustomerList so that customers with the highest spend appear first.
  • In your main function, create a CustomerList with at least four different customers and use sort.Sort() to order them.
  • Print the sorted list to the console to verify the order.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.