Циклический импорт и отсутствие генериков, вызывающих головную боль - PullRequest
0 голосов
/ 03 декабря 2018

Скажем, у меня есть два файла в golang:

// main/a/a.go
import "main/b"

type Model struct {
    ID         int    `json:"id"`
    Me         int    `json:"me"`
    You        int    `json:"you"`
}

func zoom(v b.Injection){

}

func Start(){
  // ...
}

, а затем второй файл выглядит так:

// main/b/b.go
import "main/a"

type Injection struct {
    ModelA a.Model
}


func GetInjection() Injection {
    return Injection{
        ModelA: a.Start(),
    }
}

, так что, как вы можете видеть, это циклический импорт, каждыйфайл импортирует другой.Поэтому мне нужно использовать третий файл, и эти два файла импортировать третий файл.

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

Мой первый шаг - переместить тип Injection в 3-й файл:

   // main/c/c.go

    type Injection struct {
        ModelA interface{} // formerly a.Model
    }

, так что теперь это выглядит так:

a imports c
b imports a,c

так что больше никаких циклов, однако проблема в том, что я не знаю, как создать интерфейс для a.Model в c.go?Пустой interface{}, который я использовал выше, по обычным причинам не работает.

Как решить эту проблему циклического импорта с этими 2 исходными файлами?

1 Ответ

0 голосов
/ 03 декабря 2018

Если вы хотите, чтобы они были помещены в отдельные пакеты, вы не можете иметь Model и zoom() в одном пакете, так как zoom() относится к Injection и Injection относится к Model.

Таким образом, возможное решение - поместить Model в пакет a, zoom() в пакет b и Injection в пакет c.c.Injection может означать a.Model, b.zoom() может обозначать c.Injection.В этом нет круга:

   b.zoom() -------->   c.Injection ---------> a.Model

Я предполагаю, что в вашем реальном коде есть другие ссылки, которых нет в вопросе, которые могут помешать этому, но вы можете перемещать «вещи» между пакетами, илиВы можете разбить его на более.

Кроме того, если вещи связаны так "плотно", вам действительно следует подумать о том, чтобы поместить их в один и тот же пакет, и тогда проблем не будет.

Еще один способ решить проблему кругового импорта - это ввести интерфейсы.Например, если ваша функция zoom() не будет ссылаться на Injection, пакет, содержащий Model и zoom(), не должен будет ссылаться на пакет Injection.

Проверьте, что нужно zoom()делать с Injection.Если это вызовы метода, это уже хорошо.Если нет, добавьте методы к Injection.Затем вы можете определить интерфейс в пакете zoom(), содержащем методы, которые zoom() должен вызывать, и изменить его тип параметра на этот интерфейс.Реализация интерфейсов в Go неявна, декларация намерения отсутствует.Таким образом, вы можете удалить ссылку в типе параметра, тем не менее, вы сможете передать Injection значения в zoom().

Также связанные, проверьте мысли Дэйва Чейни об организации кода :

Я считаю, что код должен быть организован в имена пакетов для того, что пакет предоставляет, а не для того, что он содержит.Иногда это может быть тонким, но, как правило, нет.

Например, http предоставляет клиентов и серверы http.

В качестве контрпримера, пакет utils - это плохое имя, да, он предоставляет утилиты,но вы не знаете, что из названия, по правде говоря, этот пакет назван так, как он содержится.

Если ваш проект - библиотека, он должен содержать один пакет (исключая примеры и, возможно, служебные команды), если онсодержит больше пакетов, что является признаком того, что библиотека пытается сделать слишком много вещей.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...