Как я могу поддерживать несколько версий одного и того же интерфейса?

Я пишу модуль go, который реализует структуру, удовлетворяющую интерфейсу. Мы хотим поддерживать только одну версию нашей библиотеки, но наши клиенты используют несколько версий одной из наших зависимостей.

Зависимость предоставляет интерфейс, который мы хотим реализовать, например этот.

type SuperCoolInterface interface {
    DoOldCoolThing(value string)
}

А наша реализация такая.

type SuperCoolImpl struct {}

func (sc *SuperCoolImpl) DoOldCoolThing(value string) {}

Новая версия зависимости добавляет новый тип в модуль типов.

type NewType struct {
  value string
}

Зависимость добавляет метод к интерфейсу.

type SuperCoolInterface interface {
    DoOldCoolThing(value string)
    DoNewCoolThing(value types.NewType)
}

Теперь, если я реализую новый метод, он не будет компилироваться со старой версией библиотеки, так как types.NewType не существует. Однако, если я не реализую новую версию, меня не удовлетворит новая версия интерфейса.

type SuperCoolImpl struct {}

func (sc *SuperCoolImpl) DoOldCoolThing(value string) {}
func (sc *SuperCoolImpl) DoNewCoolThing(value types.NewType) {}

Нужно ли нам разветвлять наш код, чтобы поддерживать эту версию? В языках с препроцессорами для этого есть простое решение, поэтому я предполагаю, что в Go должно быть решение, которого мне не хватает.

Мы планируем продолжить разработку и поддерживать обе версии, поэтому было бы неудобно обеспечивать согласованность двух разных версий. Я надеялся, что смогу сделать что-то с отражением или что-то похожее на препроцессор C, где я могу определить значение препроцессора и реализовать метод только тогда, когда мы укажем, что версия библиотеки имеет правильный тип.

Если методы делают разные вещи, создайте новый метод и оставьте старый в покое. Тогда у вас будет одна обратно совместимая версия. В противном случае у вас может быть один метод, который принимает interface {}, а затем тип переключателя внутри метода, чтобы определить, что делать. Нам нужно больше информации о том, что делают методы.

Schwern 13.02.2023 19:41

То, что делают методы, не имеет отношения к моему вопросу. Я просто пытаюсь удовлетворить интерфейс. Если я возьму interface{} вместо types.NewType, то интерфейс не удовлетворит. Я думаю, вы упускаете тот факт, что интерфейс и тип реализованы как часть зависимости, и я контролирую только реализацию.

zrbecker 13.02.2023 19:43

Корень проблемы не в двух версиях интерфейса, а в NewType. Без этого NewType вы можете просто реализовать более новую версию, и ваши клиенты, использующие более старую версию, все равно будут компилироваться. С NewType вы застряли с реализацией двух версий.

Burak Serdar 13.02.2023 19:51
Типы данных JavaScript
Типы данных JavaScript
В JavaScript существует несколько типов данных, включая примитивные типы данных и ссылочные типы данных. Вот краткое объяснение различных типов данных...
Как сделать движок для футбольного матча? (простой вариант)
Как сделать движок для футбольного матча? (простой вариант)
Футбол. Для многих людей, живущих на земле, эта игра - больше, чем просто спорт. И эти люди всегда мечтают стать футболистом или менеджером. Но, к...
Знайте свои исключения!
Знайте свои исключения!
В Java исключение - это событие, возникающее во время выполнения программы, которое нарушает нормальный ход выполнения инструкций программы. Когда...
CSS Flex: что должен знать каждый разработчик
CSS Flex: что должен знать каждый разработчик
CSS Flex: что должен знать каждый разработчик Модуль flexbox, также известный как гибкий модуль разметки box, помогает эффективно проектировать и...
Введение в раздел "Заголовок" в HTML
Введение в раздел "Заголовок" в HTML
Говорят, что лучшее о человеке можно увидеть только изнутри, и это относится и к веб-страницам HTML! Причина, по которой некоторые веб-страницы не...
1
3
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я нашел решение, которое работает для моей ситуации.

Спасибо @Burak Serdar за то, что направил меня в правильном направлении.

Мое решение состоит в том, чтобы поместить старую реализацию в пакет impl/v0, а новую реализацию — в пакет impl/v1.

Клиенты, использующие старую версию зависимости, будут использовать impl/v0, а клиенты, использующие новую версию зависимости, будут использовать impl/v1.

Поскольку golang компилирует только тот код, который был импортирован напрямую, будет скомпилирован только пакет с правильной версией интерфейса, поэтому он будет успешно компилироваться в обоих направлениях.

Это избавляет меня от беспокойства по поводу необходимости разветвления всей библиотеки.

Обновлено: если кто-то использует это решение, есть одна проблема, если вы в настоящее время проводите свои тесты с помощью go test ./.... Кажется, что эта команда пытается собрать каждый модуль, независимо от того, есть ли в нем тесты или нет.

Но вы можете исключить тесты с помощью go test $(go list ./... | grep -v <PATH_TO_IGNORE>), а затем запустить эти тесты для правильной версии в другой команде.

Другие вопросы по теме