Stringer & Error Interfaces
Part of the Object Oriented Programming section of Coddy's GO journey — lesson 32 of 107.
Go's standard library defines two interfaces that you'll use constantly: fmt.Stringer and error. Both are simple single-method interfaces that give your types powerful integration with Go's built-in functionality.
The Stringer interface lives in the fmt package and requires just one method:
type Stringer interface {
String() string
}When you implement String() on your type, functions like fmt.Println automatically use it to display your value:
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}
func main() {
p := Person{Name: "Alice", Age: 30}
fmt.Println(p) // Alice (30 years old)
}The error interface is equally simple, requiring an Error() method that returns a string:
type error interface {
Error() string
}Any type with an Error() method can be used as an error value in Go. This lets you create custom error types with additional context:
type ValidationError struct {
Field string
Message string
}
func (e ValidationError) Error() string {
return fmt.Sprintf("%s: %s", e.Field, e.Message)
}
func main() {
err := ValidationError{Field: "email", Message: "invalid format"}
fmt.Println(err) // email: invalid format
}These two interfaces demonstrate Go's philosophy: small, focused interfaces that unlock powerful behavior through implicit implementation.
Challenge
EasyLet's build a temperature monitoring system that uses both the Stringer and error interfaces to provide readable output and meaningful error handling.
You'll organize your code across two files:
temperature.go: Create aTemperaturestruct withValue(float64) andUnit(string) fields. Implement theString()method so that when printed, it displays the temperature in a human-readable format. Also create aTemperatureErrorstruct withTemp(float64) andReason(string) fields, and implement theError()method to provide descriptive error messages.main.go: Create a function calledValidateTemperaturethat takes aTemperatureand returns an error if the temperature is invalid. A temperature is invalid if it's below absolute zero (-273.15 for Celsius, -459.67 for Fahrenheit). If valid, the function returnsnil. Read temperature data from input, create a Temperature, validate it, and print appropriate output.
The following inputs will be provided:
- Line 1: Temperature value (float)
- Line 2: Unit (
Cfor Celsius orFfor Fahrenheit)
Your String() method should return the format:
[Value] degrees [Unit]Where Unit is the full word "Celsius" or "Fahrenheit" based on the input.
Your Error() method should return the format:
invalid temperature [Temp]: [Reason]If the temperature is valid, print the Temperature using fmt.Println (which will use your String() method). If invalid, print the error (which will use your Error() method).
For example, given 25.5 and C, your output should be:
25.5 degrees CelsiusGiven -500 and F, your output should be:
invalid temperature -500: below absolute zeroUse "below absolute zero" as the reason when the temperature is too low.
Cheat sheet
Go's standard library defines two essential interfaces: fmt.Stringer and error.
The Stringer Interface
The Stringer interface from the fmt package requires one method:
type Stringer interface {
String() string
}When you implement String() on your type, functions like fmt.Println automatically use it:
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}
func main() {
p := Person{Name: "Alice", Age: 30}
fmt.Println(p) // Alice (30 years old)
}The error Interface
The error interface requires an Error() method that returns a string:
type error interface {
Error() string
}Any type with an Error() method can be used as an error value, allowing custom error types with additional context:
type ValidationError struct {
Field string
Message string
}
func (e ValidationError) Error() string {
return fmt.Sprintf("%s: %s", e.Field, e.Message)
}
func main() {
err := ValidationError{Field: "email", Message: "invalid format"}
fmt.Println(err) // email: invalid format
}Try it yourself
package main
import (
"fmt"
)
// ValidateTemperature checks if a temperature is valid
// Returns an error if the temperature is below absolute zero
// Absolute zero: -273.15 for Celsius, -459.67 for Fahrenheit
func ValidateTemperature(t Temperature) error {
// TODO: Implement validation logic
// Check if temperature is below absolute zero based on unit
// Return a TemperatureError if invalid, nil if valid
return nil
}
func main() {
var value float64
var unit string
fmt.Scanln(&value)
fmt.Scanln(&unit)
// TODO: Create a Temperature struct with the input values
// TODO: Validate the temperature using ValidateTemperature
// TODO: If there's an error, print the error
// Otherwise, print the temperature (which will use String() method)
}
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 Parser3Pointers & 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