🎓 A1Learner
🔍
0 of 55 lessons completed

Zig Project: Bank Account

A bank account program is a small model of an account that holds money and records what changed. This project builds an account struct with deposit and withdraw methods, and it refuses a withdrawal the balance cannot cover.

Deposit adds to the balance

The account starts at 100 and the deposit method adds 50 through a pointer to the struct. The printed balance proves the method changed the stored value.

const std = @import("std");

const Account = struct {
    balance: i32,
    note: ?[]const u8 = null,

    pub fn deposit(self: *Account, amount: i32) void {
        self.balance += amount;
        self.note = "deposit";
    }
};

pub fn main() !void {
    const out = std.io.getStdOut().writer();
    var acct = Account{ .balance = 100 };
    acct.deposit(50);
    try out.print("Balance: {d}\n", .{acct.balance});
}

A withdrawal the balance cannot cover is blocked

The first withdrawal of 30 succeeds and leaves 70. The second asks for 500, so catch prints the error name and the balance stays at 70.

const std = @import("std");

const Account = struct {
    balance: i32,
    note: ?[]const u8 = null,

    pub fn withdraw(self: *Account, amount: i32) error{InsufficientFunds}!void {
        if (amount > self.balance) {
            return error.InsufficientFunds;
        }
        self.balance -= amount;
        self.note = "withdraw";
    }
};

pub fn main() !void {
    const out = std.io.getStdOut().writer();
    var acct = Account{ .balance = 100 };
    try acct.withdraw(30);
    try out.print("After withdraw: {d}\n", .{acct.balance});
    acct.withdraw(500) catch |err| {
        try out.print("Blocked: {s}\n", .{@errorName(err)});
    };
    try out.print("Balance stays: {d}\n", .{acct.balance});
}

The note is null until the first transaction

The note field starts as null, so the first check prints none. After a deposit of 25, the same check prints the stored note.

const std = @import("std");

const Account = struct {
    balance: i32,
    note: ?[]const u8 = null,

    pub fn deposit(self: *Account, amount: i32) void {
        self.balance += amount;
        self.note = "deposit";
    }
};

pub fn main() !void {
    const out = std.io.getStdOut().writer();
    var acct = Account{ .balance = 100 };
    if (acct.note) |n| {
        try out.print("Last transaction: {s}\n", .{n});
    } else {
        try out.print("Last transaction: none\n", .{});
    }
    acct.deposit(25);
    if (acct.note) |n| {
        try out.print("Last transaction: {s}\n", .{n});
    } else {
        try out.print("Last transaction: none\n", .{});
    }
    try out.print("Balance: {d}\n", .{acct.balance});
}

Example

const std = @import("std");

const Account = struct {
    balance: i32,
    note: ?[]const u8 = null,

    pub fn deposit(self: *Account, amount: i32) void {
        self.balance += amount;
        self.note = "deposit";
    }

    pub fn withdraw(self: *Account, amount: i32) error{InsufficientFunds}!void {
        if (amount > self.balance) {
            return error.InsufficientFunds;
        }
        self.balance -= amount;
        self.note = "withdraw";
    }
};

pub fn main() !void {
    const out = std.io.getStdOut().writer();
    var acct = Account{ .balance = 200 };
    try out.print("Start: {d}\n", .{acct.balance});
    acct.deposit(75);
    try out.print("After deposit: {d}\n", .{acct.balance});
    try acct.withdraw(40);
    try out.print("After withdraw: {d}\n", .{acct.balance});
    acct.withdraw(1000) catch |err| {
        try out.print("Withdraw 1000 blocked: {s}\n", .{@errorName(err)});
    };
    try out.print("Final balance: {d}\n", .{acct.balance});
    if (acct.note) |n| {
        try out.print("Last transaction: {s}\n", .{n});
    }
}

Key points

  • Account struct: fields hold the balance and a note about the last transaction.
  • Deposit: a method that adds an amount to the balance.
  • Withdraw: a method that takes an amount away only when the balance covers it.
  • InsufficientFunds: a custom error returned when a withdrawal is too large.
  • Optional note: the note field holds text, or null before any transaction happens.

In this example, the account starts with a balance of 200 and a null note. A deposit of 75 raises the balance to 275, and a withdrawal of 40 lowers it to 235. The withdrawal of 1000 returns error.InsufficientFunds, catch prints its name, and the balance stays at 235. The statement ends with the note from the last successful transaction, withdraw.

Note

a failed withdrawal returns the error before changing anything, so the balance stays correct.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

What happens when withdraw is asked for more than the balance holds?