Go中的lambda表达式之类的东西(合并相似的方法)

I have a struct in Go which has more than ten methods. And all of them are almost the same. In fact, the difference is only in one line.

Let's see the simplified example. Here is the first method:

func (s *service) GetUser(i int, s string) (*SomeObject, error) {
    CommonMethod1()
    CommonMethod2()

    user, err := s.internalLayer.GetUser(i, s)

    if err != nil {
        CommonMethod3()
    }
    return user, err
}

And the second one:

func (s *service) CheckUser(i int) (bool, error) {
    CommonMethod1()
    CommonMethod2()

    exists, err := s.internalLayer.CheckUser(i)

    if err != nil {
        CommonMethod3()
    }
    return exists, err
}

And there are almost 10 others with a lot of copy and paste. I'd like to ameliorate this code and the idea is to create some common method that I'll call everywhere.

It should

  • call CommonMethod1()
  • call CommonMethod2()
  • call some method that I pass to it in the parameter
  • call CommonMethod3() in case of error
  • return parameters

Can you tell me if it's possible to implement in Go such common method?

user, err := s.GetUser(i, s)
exists, err := s.CheckUser(i)

Has different parameters count and different return types.

You can DRY it using closures:

func GetUser2(i int, s string) (*User, error) {
    var u *User
    err := do(func() error {
        var err error
        u, err = getUser(i, s)
        return err
    })
    return u, err
}

func CheckUser2(i int) (bool, error) {
    var b bool
    err := do(func() error {
        var err error
        b, err = checkUser(i)
        return err
    })
    return b, err
}

func do(f func() error) error {
    CommonMethod1()
    CommonMethod2()

    err := f()
    if err != nil {
        CommonMethod3()
    }
    return err
}

If CommonMethod1() and CommonMethod2() calls do not have to precede the calls to the internal layer, basically they can be incorporated into a check function, and you don't even need closures or function values (there's also no need to return the passed error from check()):

func (s *service) GetUser(i int, s string) (*SomeObject, error) {
    user, err := s.internalLayer.GetUser(i, s)
    check(err)
    return user, err
}

func (s *service) CheckUser(i int) (bool, error) {
    exists, err := s.internalLayer.CheckUser(i)
    check(err)
    return exists, err
}

func check(err error) {
    CommonMethod1()
    CommonMethod2()
    if err != nil {
        CommonMethod3()
    }
}

If CommonMethod1() and CommonMethod2() calls must precede the calls to the internal layer, then you may use closures, but using named result parameters simplifies the code, and again, it's unnecessary to return the error from the common function:

func (s *service) GetUser(i int, s string) (user *SomeObject, err error) {
    do(func() error {
        user, err = s.internalLayer.GetUser(i, s)
        return err
    })
    return
}

func (s *service) CheckUser(i int) (exists bool, err error) {
    do(func() error {
        exists, err = s.internalLayer.CheckUser(i)
        return err
    })
    return
}

func do(f func() error) {
    CommonMethod1()
    CommonMethod2()

    if err := f(); err != nil {
        CommonMethod3()
    }
}