package pointers_errors import ( "errors" "fmt" ) type Stringer interface { String() string } // creating a new type from an existing on // The idea being it could be more descriptive // but also you can declare methods on them // which can be used to add domain specific functionality type Bitcoin int // this let's us use fmt strings with %s on the Bitcoin type func (b Bitcoin) String() string { return fmt.Sprintf("%d BTC", b) } type Wallet struct { balance Bitcoin } func (w *Wallet) Deposit(amount Bitcoin) { // Need a pointer because the func args are copied // so w Wallet is a copy of wallet. Not the actually refernce to the // wallet that Deposit was called on. // Notice we don't have to derefence the pointer like in Balance because // in go https://go.dev/ref/spec#Method_values struct pointers are automatically // derefenced w.balance += amount } // Technically you do not need to change Balance to use a pointer receiver as taking a copy of the balance is fine. However, by convention you should keep your method receiver types the same for consistency. func (w *Wallet) Balance() Bitcoin { // dereferences the pointer // which as stated above didn't need to happen because go automatically // dereferences struct pointers. return (*w).balance } func (w *Wallet) Withdraw(amount Bitcoin) error { if amount > w.balance { return errors.New("Withdraw operation failed. Insufficient funds") } w.balance -= amount return nil }