Есть ли хороший совет о том, как избежать цикла импорта в Go?

Я работаю над проектом Go в течение месяца. Хорошо, что Go действительно очень эффективен. Но после месяца разработки у меня уже есть тысячи строк кода и много packages. Чтобы избежать цикла импорта, для меня серьезной проблемой является то, что каждый раз, когда я получаю ошибку цикла импорта, я понятия не имею, в чем может быть проблема в первый раз.

Компилятор Go также имеет очень простое уведомление, которое всегда недостаточно хорошо для быстрого обнаружения проблемы, например: main.go:7:3: import cycle not allowed. Это только поможет вам узнать, какой файл может вызвать проблему, но не более того. Поскольку отношения import становятся все более и более сложными по мере роста кода, мне не терпится узнать, как более эффективно избежать цикла импорта в Go. Любая помощь горячо приветствуется.


person Reck Hou    schedule 23.04.2013    source источник


Ответы (4)


go list -f '{{join .Deps "\n"}}' <import-path>

Покажет зависимости импорта для пакета в <import-path> - или в текущем каталоге, если <import-path> оставить пустым. Альтернативно

go list -f '{{join .DepsErrors "\n"}}' <import-path>

надеюсь, покажет некоторую полезную информацию в вашем случае. См. также вывод

go help list

для получения дополнительной информации об инструменте списка перехода.

person zzzz    schedule 23.04.2013
comment
Определенно полезно знать, на самом деле, я даже не знал о списке действий. - person mna; 23.04.2013
comment
Более новые версии go предоставляют больше информации о том, откуда берется цикл импорта. - person MattyW; 03.03.2014

Чтобы дополнить ответ jnml (который помогает «отлаживать» проблемы с циклическими ссылками), вы можете использовать инверсию зависимостей, чтобы разорвать эти циклы, в сочетании с внедрением зависимостей. В приложении я всегда стараюсь следовать рекомендациям Чистая архитектура — см. здесь для перехода -конкретный пример - и я считаю, что "недекларативная реализация" интерфейсов Go (то есть вам не нужно явно указывать type MyStruct struct implements IfceSomething) делает это очень простым.

Итак, если у вас есть пакеты A -> B -> C -> A, вы создаете InterfaceA (некоторое релевантное имя, очевидно, больше связанное с поведением, чем с пакетом :) в пакете C и делаете его зависимым от этого интерфейса, а не от пакета A, и вы убедитесь, что пакет A "реализует" этот интерфейс.

Затем вам просто нужно предоставить конкретную реализацию от A до C в какой-то момент (здесь много возможностей, я обычно делаю этот «склеивающий» код в основном пакете, который знает обо всех зависимостях).

person mna    schedule 23.04.2013

Поскольку отношения импорта становятся все более и более сложными по мере роста кода, мне не терпится узнать, как более эффективно избежать цикла импорта в Go.

Другой вариант — визуализировать зависимости в вашем проекте. Это можно сделать с помощью инструмента командной строки godepgraph. Вы можете установить его с помощью:

go get -u github.com/kisielk/godepgraph

А затем используйте его для поиска циклов импорта в своем приложении с помощью другого инструмента командной строки graphvis. Имея эти инструменты, вы можете визуализировать зависимости пакетов:

godepgraph -s path/to/my/package | dot -Tpng -o godepgraph.png
open ./godepgraph.png

чтобы найти циклы в моем коде: введите здесь описание изображения

person skovtunenko    schedule 26.03.2018

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

Model -> Field  (Uses A) -- Needs to import "System"
Model -> System (Defines A) -- But needs to import "Field"
----------Move type A Struct A.go to top of module----------
----------This is what the Model Dir looks like now---------
Model -> A
Model -> Field
Model -> System

Теперь зависимости разделены, и дети могут свободно использовать A. Это может не помочь с визуализацией зависимостей или быть хорошим решением на основе инструментов, но еще раз, если вы достаточно отделите свою логику и создадите подкомпоненты, вы должны довольно быстро сойтись в цикле. В противном случае, если вы используете визуализатор дерева, я бы сказал, что это последнее средство и результат плохого дизайна/недостаточного количества подкомпонентов.

person Brian Anderson    schedule 03.01.2021