Golang Интерфейс с функциями, получающими указанные аргументы интерфейса - PullRequest
0 голосов
/ 03 августа 2020

Я пытаюсь использовать интерфейсы в Go, чтобы получить два преимущества:

  1. Защитить себя от смешивания переменных порядка
  2. Сделать пакет независимым друг от друга, поэтому один день, я могу легко заменить один из них.

В моем конкретном случае я могу найти обходной путь, но я не могу понять, почему тот способ, который я пытаюсь, не работает, это кажется простым и логичным.

Вот что я делаю.

В одном пакете (именованные обработчики) у меня есть интерфейс, описывающий нужную мне функцию, просто что-то получает Account.

package handlers

type Accounter interface {
    AddAccount(a Account)
}

type Account interface {
    AccountID() int64
    UserID() int64
    OtherID() int64

}

В другом пакете моей программы (с именем accounter) у меня есть функция, соответствующая интерфейсу, и определение интерфейса Account, чтобы избежать импорта этого интерфейса из первого пакета.

package accounter

type Account interface {
    AccountID() int64
    UserID() int64
    OtherID() int64
}

func (x *accounter) AddAccount(a Account) {
...
}

Но go vet сообщает мне, что Я не могу сделать такое:

configure_stats_loader.go:109:64: cannot use x (type *accounter.Accounter) as type handlers.Accounter in argument to handlers.AddAccHandler:
    *accounter.Accounter does not implement handlers.Accounter (wrong type for AddAccount method)
        have AddAccount(accounter.Account)
        want AddAccount(handlers.Account)

В этом случае у меня есть решения:

  1. Импортировать Account интерфейс из одного из пакетов.
  2. Определить функцию получения значений в стандарте go тип например, (UserID, AccoutID, OtherID int64).

В первом случае я теряю независимость в пакетах, и в будущем я не смогу заменить интерфейс Accounter, не переписав код (не так много кода, но все же) , во втором случае, если у меня будет много похожих методов и много параметров в Account, я могу случайно перепутать порядок переменных. Например, случайно используйте AccountID как UserID.

А теперь вопрос: есть ли способ получить все преимущества? Получите защиту от смешивания порядка переменных и избегайте импорта из одного пакета в другой.

1 Ответ

1 голос
/ 03 августа 2020

Echoing @ Mar c комментариев, "сторонний" пакет идеально подходит для определения общих типов. Это обычная практика, особенно при работе с gRP C сгенерированным кодом .

Также согласно Эффективным Go сохраняйте короткие интерфейсы:

Интерфейсы только с одним или двумя методами распространены в Go code

Так что избегайте трудоемких определений геттеров / сеттеров - и сосредоточьтесь на более крупных операциях. Поэтому я бы предложил в вашем пакете "типы":

package mydefs

// concrete type: used for Creation and lookup
type Account struct {
    ID      int64
    UserID  int64
    OtherID int64
}

// abstract interface: keep method list short
type Accounter interface {
    Add(a Account) error             //
    Get(a Account) (Account, error)  // use concrete type as a lookup request type
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...