2017-07-05 1 views
2

J'ai une structure dans Go qui a plus de dix méthodes. Et tous sont presque les mêmes. En fait, la différence est seulement dans une ligne.Quelque chose comme les expressions lambda dans Go (fusionner des méthodes similaires)

Voyons l'exemple simplifié. Voici la première méthode:

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 
} 

Et le second:

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

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

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

Et il y a près de 10 autres avec beaucoup de copier et coller. Je voudrais améliorer ce code et l'idée est de créer une méthode commune que j'appellerai partout.

Il devrait

  • appel CommonMethod1()
  • appel CommonMethod2()
  • appel d'une méthode que je passe à dans le paramètre
  • appel CommonMethod3() en cas d'erreur
  • paramètres de retour

Pouvez-vous me dire s'il est possible d'implémenter cette méthode commune dans Go?

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

A différents paramètres comptent et différents types de retour.

+1

Dans vos exemples, chaque méthode appelle inconditionnellement elle-même, est pas une "récursivité" sans fin? – icza

+0

Bonne remarque. Je l'ai simplifié beaucoup. En fait, il appelle une couche interne. 's.internalLayer.CheckUser (i)' Corrigé. – Vitalii

Répondre

1

Vous pouvez sécher à l'aide de la fermeture:

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 
} 
3

Si CommonMethod1() et CommonMethod2() appels ne doivent pas précéder les appels à la couche interne, au fond, ils peuvent être incorporés dans une fonction de contrôle, et vous ne même besoin des fermetures ou des valeurs de fonction (il n'y a pas non plus besoin de retourner l'erreur passée de 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() 
    } 
} 

Si CommonMethod1() et CommonMethod2() appels doivent précéder les appels à la couche interne, alors vous pouvez utiliser des fermetures, mais en utilisant named result parameters simplifie le code, et encore une fois, il est inutile de renvoyer l'erreur de la fonction commune:

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() 
    } 
}