-
-
Notifications
You must be signed in to change notification settings - Fork 713
Add solution for Challenge 7 by kiramux #733
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
a38df2f
Add solution for Challenge 7
go-interview-practice-bot[bot] f68b7ed
fix Transfer()
kiramux a1bfc25
fix some mistakes and add defensive programming for duplicate IDs
kiramux 9bc7c2f
fix some mistakes
kiramux 95d99c8
translate comments in lines 78-114
kiramux File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,254 @@ | ||
| // Package challenge7 contains the solution for Challenge 7: Bank Account with Error Handling. | ||
| package challenge7 | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "sync" | ||
| // Add any other necessary imports | ||
| ) | ||
|
|
||
| // BankAccount represents a bank account with balance management and minimum balance requirements. | ||
| type BankAccount struct { | ||
| ID string | ||
| Owner string | ||
| Balance float64 | ||
| MinBalance float64 | ||
| mu sync.Mutex // For thread safety | ||
| } | ||
|
|
||
| // Constants for account operations | ||
| const ( | ||
| MaxTransactionAmount = 10000.0 // Example limit for deposits/withdrawals | ||
| ) | ||
|
|
||
| // Custom error types | ||
|
|
||
| // AccountError is a general error type for bank account operations. | ||
| type AccountError struct { | ||
| Code string | ||
| Message string | ||
| AccountID string | ||
| } | ||
|
|
||
| func (e *AccountError) Error() string { | ||
| if e.AccountID != "" { | ||
| return fmt.Sprintf("[%s] AccountID: %s, %s", e.Code, e.AccountID, e.Message) | ||
| } | ||
| return fmt.Sprintf("[%s] %s", e.Code, e.Message) | ||
| } | ||
|
|
||
| // InsufficientFundsError occurs when a withdrawal or transfer would bring the balance below minimum. | ||
| type InsufficientFundsError struct { | ||
| Code string | ||
| Message string | ||
| MinBalance float64 | ||
| } | ||
|
|
||
| func (e *InsufficientFundsError) Error() string { | ||
| return fmt.Sprintf("[%s] %s, your balance is less than the min balance: %.2f", e.Code, e.Message, e.MinBalance) | ||
| } | ||
|
|
||
| // NegativeAmountError occurs when an amount for deposit, withdrawal, or transfer is negative. | ||
| type NegativeAmountError struct { | ||
| Code string | ||
| Message string | ||
| Amount float64 | ||
| } | ||
|
|
||
| func (e *NegativeAmountError) Error() string { | ||
| return fmt.Sprintf("[%s] %s, provided number: %.2f", e.Code, e.Message, e.Amount) | ||
| } | ||
|
|
||
| // ExceedsLimitError occurs when a deposit or withdrawal amount exceeds the defined limit. | ||
| type ExceedsLimitError struct { | ||
| Code string | ||
| Message string | ||
| Amount float64 | ||
| } | ||
|
|
||
| func (e *ExceedsLimitError) Error() string { | ||
| return fmt.Sprintf("[%s] %s, provided number: %.2f, the limit is %.2f", e.Code, e.Message, e.Amount, MaxTransactionAmount) | ||
| } | ||
|
|
||
| // NewBankAccount creates a new bank account with the given parameters. | ||
| // It returns an error if any of the parameters are invalid. | ||
| func NewBankAccount(id, owner string, initialBalance, minBalance float64) (*BankAccount, error) { | ||
| // Determine the validity of the parameters. | ||
|
|
||
| // Validate accountID | ||
| if id == "" { | ||
| return nil, &AccountError{ | ||
| Code: "INVALID_ACCOUNT_ID", | ||
| Message: "account ID cannot be empty", | ||
| AccountID: id, | ||
| } | ||
| } | ||
|
|
||
| // Validate owner | ||
| if owner == "" { | ||
| return nil, &AccountError{ | ||
| Code: "INVALID_OWNER", | ||
| Message: "owner name cannot be empty", | ||
| AccountID: id, | ||
| } | ||
| } | ||
|
|
||
| // Validate initial balance | ||
| if initialBalance < 0 { | ||
| return nil, &NegativeAmountError{ | ||
| Code: "INVALID_INITIAL_BALANCE", | ||
| Message: "initial balance cannot be negative", | ||
| Amount: initialBalance, | ||
| } | ||
| } | ||
|
|
||
| // Validate minimum balance | ||
| if minBalance < 0 { | ||
| return nil, &NegativeAmountError{ | ||
| Code: "INVALID_MIN_BALANCE", | ||
| Message: "min balance cannot be negative", | ||
| Amount: minBalance, | ||
| } | ||
| } | ||
|
|
||
| // Compare initial balance and minimum balance | ||
| if initialBalance < minBalance { | ||
| return nil, &InsufficientFundsError{ | ||
| Code: "INSUFFICIENT_FUND", | ||
| Message: fmt.Sprintf("the initialBalance: %.2f is less than minBalance: %.2f", initialBalance, minBalance), | ||
| MinBalance: minBalance, | ||
| } | ||
| } | ||
|
|
||
| return &BankAccount{ | ||
| ID: id, | ||
| Owner: owner, | ||
| Balance: initialBalance, | ||
| MinBalance: minBalance, | ||
| }, nil | ||
| } | ||
|
|
||
| // Deposit adds the specified amount to the account balance. | ||
| // It returns an error if the amount is invalid or exceeds the transaction limit. | ||
| func (a *BankAccount) Deposit(amount float64) error { | ||
| if amount < 0 { | ||
| return &NegativeAmountError{ | ||
| Code: "INVALID_DEPOSIT_AMOUNT", | ||
| Message: "deposit amount cannot be negative", | ||
| Amount: amount, | ||
| } | ||
| } else if amount > MaxTransactionAmount { | ||
| return &ExceedsLimitError{ | ||
| Code: "EXCEED_LIMIT", | ||
| Message: "deposit amount cannot exceed the limit", | ||
| Amount: amount, | ||
| } | ||
| } | ||
|
|
||
| a.mu.Lock() | ||
| defer a.mu.Unlock() | ||
|
|
||
| a.Balance += amount | ||
| return nil | ||
| } | ||
|
|
||
| // Withdraw removes the specified amount from the account balance. | ||
| // It returns an error if the amount is invalid, exceeds the transaction limit, | ||
| // or would bring the balance below the minimum required balance. | ||
| func (a *BankAccount) Withdraw(amount float64) error { | ||
| if amount < 0 { | ||
| return &NegativeAmountError{ | ||
| Code: "INVALID_WITHDRAW_AMOUNT", | ||
| Message: "withdraw amount cannot be negative", | ||
| Amount: amount, | ||
| } | ||
| } else if amount > MaxTransactionAmount { | ||
| return &ExceedsLimitError{ | ||
| Code: "EXCEED_LIMIT", | ||
| Message: "withdraw amount cannot exceed the limit", | ||
| Amount: amount, | ||
| } | ||
| } | ||
|
|
||
| a.mu.Lock() | ||
| defer a.mu.Unlock() | ||
| remain := a.Balance - amount | ||
| if remain < a.MinBalance { | ||
| return &InsufficientFundsError{ | ||
| Code: "INSUFFICIENT_FUNDS", | ||
| Message: "account balance cannot be less than min amount", | ||
| MinBalance: a.MinBalance, | ||
| } | ||
| } | ||
| a.Balance = remain | ||
| return nil | ||
| } | ||
|
|
||
| // Transfer moves the specified amount from this account to the target account. | ||
| // It returns an error if the amount is invalid, exceeds the transaction limit, | ||
| // or would bring the balance below the minimum required balance. | ||
| func (a *BankAccount) Transfer(amount float64, target *BankAccount) error { | ||
| if amount < 0 { | ||
| return &NegativeAmountError{ | ||
| Code: "INVALID_TRANSFER_AMOUNT", | ||
| Message: "transfer amount cannot be negative", | ||
| Amount: amount, | ||
| } | ||
| } else if amount > MaxTransactionAmount { | ||
| return &ExceedsLimitError{ | ||
| Code: "EXCEED_LIMIT", | ||
| Message: "transfer amount cannot exceed the limit", | ||
| Amount: amount, | ||
| } | ||
| } | ||
|
|
||
| // check target account is valid or not | ||
| switch target { | ||
| case nil: | ||
| return &AccountError{ | ||
| Code: "INVALID_TARGET_ACCOUNT", | ||
| Message: "target account is not existed", | ||
| AccountID: "", | ||
| } | ||
| case a: | ||
| return &AccountError{ | ||
| Code: "INVALID_TARGET_ACCOUNT", | ||
| Message: "target account cannot be the from account", | ||
| AccountID: a.ID, | ||
| } | ||
| } | ||
|
|
||
| // The lock order is determined by the account ID number | ||
| var first, second *BankAccount | ||
| if a.ID < target.ID { | ||
| first = a | ||
| second = target | ||
| } else if a.ID > target.ID { | ||
| first = target | ||
| second = a | ||
| } else { | ||
| // a.ID == target.ID but a != target (duplicate IDs) | ||
| return &AccountError{ | ||
| Code: "DUPLICATE_ACCOUNT_ID", | ||
| Message: "source and target accounts have duplicate IDs", | ||
| AccountID: a.ID, | ||
| } | ||
| } | ||
|
|
||
| first.mu.Lock() | ||
| second.mu.Lock() | ||
| defer second.mu.Unlock() | ||
| defer first.mu.Unlock() | ||
|
|
||
| remain := a.Balance - amount | ||
| if remain < a.MinBalance { | ||
| return &InsufficientFundsError{ | ||
| Code: "INSUFFICIENT_FUNDS", | ||
| Message: "account balance cannot be less than min amount", | ||
| MinBalance: a.MinBalance, | ||
| } | ||
| } | ||
| a.Balance = remain | ||
| target.Balance += amount | ||
| return nil | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.