Menu
Coddy logo textTech

The error Interface

Part of the Object Oriented Programming section of Coddy's GO journey — lesson 52 of 107.

In Go, errors are handled through a built-in interface called error. This interface is remarkably simple—it requires just one method:

type error interface {
    Error() string
}

Any type that implements an Error() method returning a string automatically satisfies the error interface. This is Go's interface system at work—no explicit declaration needed.

The most common way to create errors is using the errors package:

import "errors"

func Divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("cannot divide by zero")
    }
    return a / b, nil
}

Go functions typically return an error as their last return value. When no error occurs, you return nil. The caller then checks if the error is non-nil before proceeding:

result, err := Divide(10, 0)
if err != nil {
    fmt.Println("Error:", err.Error())
    return
}
fmt.Println("Result:", result)

You can also use fmt.Errorf to create formatted error messages:

func GetUser(id int) (string, error) {
    if id <= 0 {
        return "", fmt.Errorf("invalid user id: %d", id)
    }
    return "Alice", nil
}

This pattern of returning errors rather than throwing exceptions is fundamental to Go. It makes error handling explicit and forces you to consider what happens when things go wrong—a key aspect of writing robust, object-oriented code.

challenge icon

Challenge

Easy

Let's build a bank account system that demonstrates Go's error handling pattern. You'll create a simple account that validates operations and returns meaningful errors when things go wrong.

You'll organize your code across two files:

  • account.go: Create a BankAccount struct with an exported Owner field (string) and an unexported balance field (float64). Implement the following:
    • NewBankAccount(owner string, initialDeposit float64) (*BankAccount, error) - a constructor that returns an error with the message "initial deposit must be positive" if the initial deposit is zero or negative. Otherwise, create and return the account.
    • Deposit(amount float64) error - adds money to the balance. Return an error with message "deposit amount must be positive" if the amount is zero or negative.
    • Withdraw(amount float64) error - removes money from the balance. Return an error with message "withdrawal amount must be positive" if the amount is zero or negative, or "insufficient funds" if the balance is less than the withdrawal amount.
    • Balance() float64 - returns the current balance
  • main.go: Read account details and transaction amounts from input. Attempt to create an account and perform operations. After each operation, print either the success message or the error message.

The following inputs will be provided:

  • Line 1: Owner name
  • Line 2: Initial deposit amount
  • Line 3: Deposit amount
  • Line 4: Withdrawal amount

For each operation, print the result:

  • After account creation: Account created for [Owner] with balance: $[balance] or Error: [error message]
  • After deposit: Deposited successfully. New balance: $[balance] or Error: [error message]
  • After withdrawal: Withdrew successfully. New balance: $[balance] or Error: [error message]

Format all balance values with two decimal places. If account creation fails, skip the remaining operations.

For example, given Alice, 100, 50, and 200, your output should be:

Account created for Alice with balance: $100.00
Deposited successfully. New balance: $150.00
Error: insufficient funds

And given Bob, -50, 25, and 10, your output should be:

Error: initial deposit must be positive

Cheat sheet

Go handles errors through the built-in error interface, which requires a single method:

type error interface {
    Error() string
}

Create errors using the errors package:

import "errors"

func Divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("cannot divide by zero")
    }
    return a / b, nil
}

Functions return errors as the last return value. Return nil when no error occurs:

result, err := Divide(10, 0)
if err != nil {
    fmt.Println("Error:", err.Error())
    return
}
fmt.Println("Result:", result)

Use fmt.Errorf for formatted error messages:

func GetUser(id int) (string, error) {
    if id <= 0 {
        return "", fmt.Errorf("invalid user id: %d", id)
    }
    return "Alice", nil
}

Try it yourself

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Read owner name
	ownerName, _ := reader.ReadString('\n')
	ownerName = strings.TrimSpace(ownerName)

	// Read initial deposit
	initialDepositStr, _ := reader.ReadString('\n')
	initialDeposit, _ := strconv.ParseFloat(strings.TrimSpace(initialDepositStr), 64)

	// Read deposit amount
	depositStr, _ := reader.ReadString('\n')
	depositAmount, _ := strconv.ParseFloat(strings.TrimSpace(depositStr), 64)

	// Read withdrawal amount
	withdrawStr, _ := reader.ReadString('\n')
	withdrawAmount, _ := strconv.ParseFloat(strings.TrimSpace(withdrawStr), 64)

	// TODO: Create a new bank account using NewBankAccount
	// If there's an error, print "Error: [error message]" and return
	// If successful, print "Account created for [Owner] with balance: $[balance]"

	// TODO: Attempt to deposit the deposit amount
	// If there's an error, print "Error: [error message]"
	// If successful, print "Deposited successfully. New balance: $[balance]"

	// TODO: Attempt to withdraw the withdrawal amount
	// If there's an error, print "Error: [error message]"
	// If successful, print "Withdrew successfully. New balance: $[balance]"

	// Remember to format balance values with two decimal places using fmt.Printf("%.2f", balance)

	_ = ownerName
	_ = initialDeposit
	_ = depositAmount
	_ = withdrawAmount
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming