Aravind Yarram
Aravind Yarram

Reputation: 80192

How to call a Go method on a struct type?

I getting the error not enough arguments in call to method expression AccountService.Open when I run the following. Run here: https://play.golang.org/p/Z9y-QIcwNy

type AccountService interface {
    Open(no string, name string, openingDate time.Time) AccountService
}

type Account struct {
    Num      string
    Name     string
    OpenDate time.Time
    Balance  float64
}

type SavingsAccount struct {
    InterestRate float32
    Account
}

type CheckingAccount struct {
    TransactionFee float32
    Account
}

func (a SavingsAccount) Open(no string, name string, openingDate time.Time) AccountService {
    return SavingsAccount{
        Account: Account{Num: no,
            Name:     name,
            OpenDate: openingDate,
        },
        InterestRate: 0.9,
    }
}
func (a CheckingAccount) Open(no string, name string, openingDate time.Time) AccountService {
    return CheckingAccount{
        Account: Account{Num: no,
            Name:     name,
            OpenDate: openingDate,
        },
        TransactionFee: 0.15,
    }
}

func main() {
    aliceAcct := AccountService.Open("12345", "Alice", time.Date(1999, time.January, 03, 0, 0, 0, 0, time.UTC))

    fmt.Println("Alice's account =", aliceAcct)
}

Upvotes: 4

Views: 3591

Answers (3)

Thundercat
Thundercat

Reputation: 121149

The result of the method expression AccountService.Open is a function with with type func(AccountService, string, string, time.Time) AccountService. The code is missing the first argument. You can call it like this:

aliceAcct := AccountService.Open(CheckingAccount{}, "12345", "Alice", time.Date(1999, time.January, 03, 0, 0, 0, 0, time.UTC))

playground example

If you have no meaningful value to use as the receiver, then use a function instead:

func OpenCheckingAccount(no string, name string, openingDate time.Time) AccountService {
    ...
}

If you need to abstract account creation, then define the service as a function:

 type AccountService func(no string, name string, openingDate time.Time) AccountType
 func OpenSavings(no string, name string, openingDate time.Time) AccountType { ... }
 func OpenChecking(no string, name string, openingDate time.Time) AccountType { ... }

The OpenSavings and OpenChecking functions can be used as an AccountService.

You will want to use different types for the service and accounts. Here, I use AccountService and AccountType. AccountType is not a very good name, but Account is already used. AccountType might be defined as the following:

type AccountType interface {
   func Deposit(int)
   func Withdraw(int)
}

Upvotes: 7

Zan Lynx
Zan Lynx

Reputation: 54383

Most Go packages do one of two things:

  1. Have a package level function such as OpenSavingsAccount that returns an open, initialized SavingsAccount.

  2. Have a default variable in the package named DefaultSavingsAccount and duplicate the SavingsAccount methods at the package level where they operate on the DefaultSavingsAccount. This is a lot of function duplication but all of the logic stays in the methods. And if the DefaultSavingsAccount is not const and is an interface type it can be replaced with another implementation.

Upvotes: 2

tier1
tier1

Reputation: 6433

Try this

acct := SavingsAccount{}
aliceAcct:= acct.Open("12345", "Alice", time.Date(1999, time.January, 03, 0, 0, 0, 0, time.UTC))
fmt.Println("Alice's account =", aliceAcct)

You need to create an instance of a struct that properly implements the AccountService interface

--Edit Working example: play.golang.org

Upvotes: 4

Related Questions