Start learning free

LESSON 400 OF 404 · PROJECTS: OBJECT-ORIENTED

Bank Account - Protect the Balance in Go

Practice

Build a BankAccount class that keeps its balance private and lets other code change it only through methods that check the rules. This is encapsulation: the object protects its own data.

Private balance. Go has no private keyword: a name that starts with a lowercase letter, like the field balance, is visible only inside its package. Methods are declared outside the struct with a receiver, func (this *BankAccount) ....

What the class must have (Go):

  • The constructor function NewBankAccount(initialBalance float64) *BankAccount: creates an account that starts with the given balance.
  • func (this *BankAccount) deposit(amount float64): adds amount to the balance. If amount is zero or negative, do nothing (no error, the balance stays the same).
  • func (this *BankAccount) withdraw(amount float64) bool: if amount is zero or negative, or larger than the balance, change nothing and return false. Otherwise subtract it from the balance and return true. Withdrawing exactly the whole balance is allowed (the balance becomes 0).
  • func (this BankAccount) getBalance() float64: returns the current balance. It is the only way for outside code to read it.

In Go you also write mainFunction(), the driver, as the last steps of the lesson. It prints the balance with %d and int(...).

The driver. You write the driver last, in mainFunction(). It runs these checks:

func mainFunction() {
    account := NewBankAccount(100.0)
    account.deposit(50.0)
    account.withdraw(30.0)
    account.withdraw(200.0)
    fmt.Printf("Balance: %d\n", int(account.getBalance()))
    account.deposit(-20.0)
    account.deposit(0.0)
    account.withdraw(-5.0)
    fmt.Printf("Balance: %d\n", int(account.getBalance()))
    if account.withdraw(120.0) {
        fmt.Println("Withdrew all")
    }
    fmt.Printf("Balance: %d\n", int(account.getBalance()))
    if !account.withdraw(1.0) {
        fmt.Println("Rejected")
    }
}

Walk through it: start with 100, deposit 50 (150), withdraw 30 (120), withdraw 200 is refused (still 120). Then deposit -20, deposit 0 and withdraw -5 are all ignored (still 120). Withdrawing 120 succeeds and empties the account, so the balance is 0, and withdrawing 1 more is refused.

Expected output:

Balance: 120
Balance: 120
Withdrew all
Balance: 0
Rejected

Both deposit and withdraw start with a guard that rejects amount <= 0. Write the guard first, then the change to the balance.

return &BankAccount{balance: initialBalance}

if amount <= 0 || amount > this.balance { return false }, then this.balance -= amount and return true.

type BankAccount struct {
    balance float64
}

func NewBankAccount(initialBalance float64) *BankAccount {
    return &BankAccount{balance: initialBalance}
}

func (this *BankAccount) deposit(amount float64) {
    if amount <= 0 {
        return
    }
    this.balance += amount
}

func (this *BankAccount) withdraw(amount float64) bool {
    if amount <= 0 || amount > this.balance {
        return false
    }
    this.balance -= amount
    return true
}

func (this BankAccount) getBalance() float64 {
    return this.balance
}



func mainFunction() {
    account := NewBankAccount(100.0)
    account.deposit(50.0)
    account.withdraw(30.0)
    account.withdraw(200.0)
    fmt.Printf("Balance: %d\n", int(account.getBalance()))
    account.deposit(-20.0)
    account.deposit(0.0)
    account.withdraw(-5.0)
    fmt.Printf("Balance: %d\n", int(account.getBalance()))
    if account.withdraw(120.0) {
        fmt.Println("Withdrew all")
    }
    fmt.Printf("Balance: %d\n", int(account.getBalance()))
    if !account.withdraw(1.0) {
        fmt.Println("Rejected")
    }
}

STEP 1 OF 25
    Ctrl + Enter to check

    Bank Account in Go

    Keep going with GoAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free