Implementing a Simple Banking System with Go Struct Methods
This challenge focuses on understanding and implementing methods for structs in Go. You will build a basic banking system where you can manage bank accounts, deposit funds, withdraw funds, and check the balance. This exercise will solidify your grasp of how to associate behavior with data structures.
Problem Description
Your task is to create a Go program that models a simple bank account. You need to define a BankAccount struct and then implement methods on this struct to perform common banking operations.
Key Requirements:
-
BankAccountStruct: Define a struct namedBankAccountthat should contain at least the following fields:accountNumber(string): A unique identifier for the account.balance(float64): The current amount of money in the account.
-
DepositMethod: Implement a method calledDepositthat takes afloat64amount as input. This method should:- Add the deposit amount to the account's
balance. - Return the new balance.
- Handle negative deposit amounts by returning an error.
- Add the deposit amount to the account's
-
WithdrawMethod: Implement a method calledWithdrawthat takes afloat64amount as input. This method should:- Subtract the withdrawal amount from the account's
balance. - Return the new balance.
- Handle withdrawal amounts that exceed the current
balanceby returning an error (insufficient funds). - Handle negative withdrawal amounts by returning an error.
- Subtract the withdrawal amount from the account's
-
GetBalanceMethod: Implement a method calledGetBalancethat takes no arguments and returns the currentbalanceof the account. -
Error Handling: All methods that can fail (Deposit, Withdraw) should return an
errortype in addition to their primary return value. If an operation is successful, the error should benil.
Expected Behavior:
- Creating a new
BankAccountshould initialize it with a starting balance (usually 0). - Deposits should correctly increase the balance.
- Withdrawals should correctly decrease the balance, but only if funds are sufficient and the amount is valid.
- Attempting invalid operations (negative deposits/withdrawals, insufficient funds) should result in appropriate errors.
Edge Cases to Consider:
- Depositing or withdrawing zero amount.
- Attempting to withdraw exactly the balance.
- Handling floating-point precision issues (though for this exercise, standard
float64operations are acceptable).
Examples
Example 1:
// Assume a BankAccount struct and its methods are defined.
account := BankAccount{accountNumber: "12345", balance: 100.0}
newBalance, err := account.Deposit(50.0)
// newBalance should be 150.0
// err should be nil
fmt.Printf("Account %s new balance after deposit: %.2f\n", account.accountNumber, newBalance)
Account 12345 new balance after deposit: 150.00
Explanation: A deposit of 50.0 is added to the initial balance of 100.0, resulting in a new balance of 150.0. The operation is successful, so no error is returned.
Example 2:
// Assume a BankAccount struct and its methods are defined.
account := BankAccount{accountNumber: "67890", balance: 75.50}
newBalance, err := account.Withdraw(100.0)
// newBalance should be 75.50 (no change)
// err should not be nil (e.g., "insufficient funds")
if err != nil {
fmt.Printf("Withdrawal failed: %v\n", err)
} else {
fmt.Printf("Account %s new balance after withdrawal: %.2f\n", account.accountNumber, newBalance)
}
Withdrawal failed: insufficient funds
Explanation: An attempt to withdraw 100.0 from an account with only 75.50 results in an "insufficient funds" error. The balance remains unchanged.
Example 3:
// Assume a BankAccount struct and its methods are defined.
account := BankAccount{accountNumber: "ABCDE", balance: 500.0}
// Attempt to deposit a negative amount
_, err := account.Deposit(-20.0)
if err != nil {
fmt.Printf("Deposit failed: %v\n", err)
} else {
fmt.Printf("Account %s balance: %.2f\n", account.accountNumber, account.GetBalance())
}
// Attempt to withdraw a negative amount
_, err = account.Withdraw(-10.0)
if err != nil {
fmt.Printf("Withdrawal failed: %v\n", err)
} else {
fmt.Printf("Account %s balance: %.2f\n", account.accountNumber, account.GetBalance())
}
// Successful withdrawal
newBalance, err := account.Withdraw(50.0)
if err != nil {
fmt.Printf("Withdrawal failed: %v\n", err)
} else {
fmt.Printf("Account %s new balance: %.2f\n", account.accountNumber, newBalance)
}
Deposit failed: cannot deposit negative amount
Withdrawal failed: cannot withdraw negative amount
Account ABCDE new balance: 450.00
Explanation: The first two operations attempt invalid actions (negative deposit and withdrawal), leading to specific errors. The final withdrawal of 50.0 is successful, reducing the balance from 500.0 to 450.0.
Constraints
- The
balancewill always be a non-negativefloat64initially. - Deposit and withdrawal amounts will be represented as
float64. - Account numbers will be strings and are assumed to be unique (though uniqueness enforcement is not part of this challenge).
- The program should be written in Go.
Notes
- You will need to define your own
BankAccountstruct. - Remember that methods in Go are functions associated with a specific type. They are defined using a receiver.
- When returning errors, use the
errorspackage (e.g.,errors.New("your error message")). - Consider using pointer receivers for methods that modify the struct's state (like
DepositandWithdraw). This is a crucial concept in Go for method implementation. - The
GetBalancemethod can use a value receiver as it only reads the state.