sort.Interface
Part of the Object Oriented Programming section of Coddy's GO journey — lesson 74 of 107.
The sort package provides another excellent example of interface-based design. To sort a custom collection, your type must implement the sort.Interface:
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}These three methods give the sort algorithm everything it needs: the collection's length, a way to compare elements, and a way to swap them. Here's how to make a slice of custom structs sortable:
type Person struct {
Name string
Age int
}
type ByAge []Person
func (a ByAge) Len() int { return len(a) }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func main() {
people := []Person{
{"Alice", 30},
{"Bob", 25},
{"Carol", 35},
}
sort.Sort(ByAge(people))
fmt.Println(people)
// [{Bob 25} {Alice 30} {Carol 35}]
}The key insight is creating a named type (ByAge) based on your slice. This lets you define different sorting behaviors for the same data. You could create ByName with a different Less implementation to sort alphabetically instead.
Once your type satisfies sort.Interface, it works with sort.Sort(), sort.Reverse(), and sort.IsSorted() automatically.
Challenge
EasyLet's build a sortable product inventory system that demonstrates the power of Go's sort.Interface! You'll create a Product type and implement multiple sorting strategies, allowing the same collection to be sorted in different ways.
You'll organize your code across two files:
product.go: Define your product type and sorting implementations.Create a
Productstruct with three fields:Name(string),Price(float64), andQuantity(int).Create two named types based on
[]Product:ByPrice- for sorting products by price in ascending orderByQuantity- for sorting products by quantity in descending order (highest quantity first)
Each type needs to implement the three methods required by
sort.Interface:Len(),Less(i, j int), andSwap(i, j int). TheLessmethod determines the sort order for each type.main.go: Build and sort your product inventory.Read a sort mode (
priceorquantity), then read a count followed by product details. Each product is provided as three lines: name, price, and quantity.Create a slice of products, sort them using the appropriate sorting type based on the mode, then print each product in this format:
[Name]: $[Price] (x[Quantity])Display prices with two decimal places.
The following inputs will be provided:
- Line 1: Sort mode (
priceorquantity) - Line 2: Number of products
- Following lines: Product details (name, price, quantity - three lines per product)
For example, given:
price
3
Laptop
999.99
5
Mouse
29.99
50
Keyboard
79.99
25Your output should be:
Mouse: $29.99 (x50)
Keyboard: $79.99 (x25)
Laptop: $999.99 (x5)And given:
quantity
3
Laptop
999.99
5
Mouse
29.99
50
Keyboard
79.99
25Your output should be:
Mouse: $29.99 (x50)
Keyboard: $79.99 (x25)
Laptop: $999.99 (x5)Notice how the same product data can be sorted differently by simply using a different named type. Once your types satisfy sort.Interface, they work seamlessly with sort.Sort() from the standard library.
Try it yourself
package main
import (
"bufio"
"fmt"
"os"
"sort"
"strconv"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Read sort mode
var mode string
fmt.Fscanln(reader, &mode)
// Read number of products
var count int
fmt.Fscanln(reader, &count)
// Read products
products := make([]Product, count)
for i := 0; i < count; i++ {
name, _ := reader.ReadString('\n')
name = name[:len(name)-1] // Remove newline
priceStr, _ := reader.ReadString('\n')
priceStr = priceStr[:len(priceStr)-1]
price, _ := strconv.ParseFloat(priceStr, 64)
qtyStr, _ := reader.ReadString('\n')
qtyStr = qtyStr[:len(qtyStr)-1]
quantity, _ := strconv.Atoi(qtyStr)
products[i] = Product{Name: name, Price: price, Quantity: quantity}
}
// TODO: Sort products based on mode
// If mode is "price", use ByPrice type
// If mode is "quantity", use ByQuantity type
// Use sort.Sort() with the appropriate type
// TODO: Print each product in the format:
// [Name]: $[Price] (x[Quantity])
// Use fmt.Printf with %.2f for price formatting
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of Go OOP
External FilesGo Workspace & ModulesPackages & ImportsExported vs Unexported NamesIntroduction to OOP in GoStructs as ClassesDefining Methods on StructsPointer vs Value ReceiversStruct InitializationConstructor FunctionsRecap - Simple Calculator4Interfaces
Introduction to InterfacesImplicit ImplementationInterface as ContractEmpty Interface (any)Type AssertionType SwitchInterface CompositionStringer & Error InterfacesRecap - Shape Calculator7Encapsulation
Exported vs Unexported FieldsPackage-Level EncapsulationGetter & Setter MethodsInformation Hiding in GoRecap - Student Records10Generics (Go 1.18+)
Introduction to GenericsType ParametersType ConstraintsGeneric StructsGeneric Methods WorkaroundRecap - Generic Collection2Types & Structs Deep Dive
Basic & Composite TypesCustom Type DefinitionsStruct TagsAnonymous StructsNested StructsZero Values & DefaultsRecap - Contact Book5Composition Over Inheritance
Why Go Has No InheritanceStruct Embedding BasicsMethod PromotionEmbedding Multiple StructsEmbedding vs AggregationShadowing Embedded MethodsRecap - Employee Hierarchy8Error Handling & OOP
The error InterfaceCustom Error TypesError Wrapping (fmt.Errorf)Sentinel Errorserrors.Is() and errors.As()Panic, Defer, and RecoverRecap - File Parser11Standard Library & OOP
io.Reader & io.Writersort.Interfacefmt.Stringer Interfaceencoding/json with Structshttp.Handler InterfaceRecap - REST API Models3Pointers & Memory
Pointer Basics in GoPointers to StructsPass by Value vs ReferenceThe new() FunctionGarbage Collection in GoRecap - Linked List Builder6Polymorphism in Go
Polymorphism via InterfacesDuck Typing in GoInterface Satisfaction RulesPolymorphic CollectionsDependency InjectionRecap - Payment Processor9Concurrency & OOP
Goroutines BasicsChannels & CommunicationBuffered vs Unbuffered ChanSelect Statementsync.Mutex & sync.RWMutexsync.WaitGroupThread-Safe Struct DesignRecap - Worker Pool