Організація багатофайкового проекту Go [закрито]


238

Примітка: це питання пов'язане з цим , але два роки - це дуже довгий час в історії Go.

Який стандартний спосіб організації проекту Go під час розробки?

Мій проект являє собою єдиний пакет mypack, тому, мабуть, я переставлю всі .go файли в mypackкаталог.

Але тоді я хотів би перевірити його під час розробки, тому мені потрібен принаймні файл, декларуючи mainпакет, щоб я міг робитиgo run trypack.go

Як я повинен це організувати? Чи потрібно мені робити go install mypackщоразу, коли захочу спробувати?


14
Ця коротка екранізація є приголомшливою: youtube.com/watch?v=XCsL89YtqCs
Matt

Це ще одне корисне посилання в розумінні того, як організувати проект з пакетами. Легше дотримуватися, ніж офіційний Як написати Go go Code Я думаю.
IamNaN

Для нової системи Go модулів ця відповідь охоплює структуру модулів, упорядкування пакетів у модулі, чи є чи не декілька модулів в одному сховищі тощо. Зрештою офіційний документ вступу «Як написати Go Code» буде оновлений для модулів , але це ще не сталося. (Якщо ви новачок Go та нові модулі Go, все-таки варто прочитати, що документ "Як написати код" перед тим, як прочитати більше про модулі, які надають більшу частину документації з модулів, передбачає знайомство з GOPATH).
типово182

Відповіді:


171

Я рекомендую переглянути цю сторінку на сторінці Як написати код

Це документує, як go buildдружньо структурувати проект , а також як писати тести. Тести не повинні бути cmd за допомогою mainпакета. Вони можуть бути просто тестованими функціями, які є частиною кожного пакету, а потім go testвідкриють їх.

Структура, запропонована у цьому посиланні у вашому запитанні, трохи застаріла, тепер із випуском Go 1. Вам більше не потрібно буде розміщувати pkgкаталог під src. Тільки 3 специфічні каталоги - це 3 у корені вашого GOPATH: bin, pkg, src. Під src ви можете просто розмістити проект mypack, а під цим - всі ваші .go файли, включаючи mypack_test.go

go build потім буде вбудований у кореневий рівень pkg та bin.

Отже, ваш GOPATH може виглядати так:

~/projects/
    bin/
    pkg/
    src/
      mypack/
        foo.go
        bar.go
        mypack_test.go

export GOPATH=$HOME/projects

$ go build mypack
$ go test mypack

Оновлення: станом на> = Перейти 1.11, тепер система Модуль є стандартною частиною інструментарію, і концепція GOPATH майже застаріла.


26
Використовуйте $ HOME замість ~ при експорті змінних.
Йохан S

6
Чому при експорті змінних $ HOME рекомендується перевищувати ~?
425nesp

8
Тому що ~ не є змінною, а лише псевдонімом.
Піг

6
@ 425nesp Йоган помиляється - це не так. Оболонки змінюються, але bash розширюється ~при встановленні змінних довкілля , і, наприклад, оболонка bourne bourne. Спробуйте самі: export BOB=~ && env | grep ^BOBпоступитьсяBOB=/your/homedir
Остін Адамс

1
$HOMEпрацює в більшості оболонок, ніж ~, наприклад, вfish
hoijui

60

jdi має правильну інформацію щодо використання GOPATH. Я б додав, що якщо ви маєте намір мати також двійковий файл, ви можете додати ще один додатковий рівень до каталогів.

~/projects/src/
    myproj/
        mypack/
            lib.go
            lib_test.go
            ...
        myapp/
            main.go

біг go build myproj/mypackбудуватиме mypackпакет разом із його залежностями, що працює go build myproj/myapp, будуватиме myappдвійковий файл разом із його залежностями, що, ймовірно, включає mypackбібліотеку.


Звичайно, це мало б сенс, якби він насправді мав основний cmd. Здавалося, він просто створює бібліотечний пакет.
jdi

50

Я вивчив цілу низку проектів Go, і тут досить багато варіацій. Ви можете начебто сказати, хто походить з C, а хто приходить з Java, оскільки колишній демпфірує майже все, що знаходиться в кореневому каталозі проектів в mainпакеті, а останні, як правило, містять все в srcкаталозі. Однак це не є оптимальним. Кожен з них має наслідки, оскільки вони впливають на шляхи імпорту та як інші можуть їх повторно використовувати.

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

myproj/
  main/
    mypack.go
  mypack.go

Де mypack.goє package mypackі main/mypack.goє (очевидно) package main.

Якщо вам потрібні додаткові файли підтримки, у вас є два варіанти. Або збережіть їх усіх у кореневому каталозі, або покладіть приватні файли підтримки у libпідкаталог. Напр

myproj/
  main/
    mypack.go
  myextras/
    someextra.go
  mypack.go
  mysupport.go

Або

myproj.org/
  lib/
    mysupport.go
    myextras/
      someextra.go
  main/
    mypack.go
  mypage.go

Покладіть файли в libкаталог лише в тому випадку, якщо вони не призначені для імпортування іншим проектом. Іншими словами, якщо це приватні файли підтримки. У цьому полягає ідея lib- відокремити публічний від приватного інтерфейсу.

Якщо зробити це таким чином, ви отримаєте хороший шлях імпорту, myproj.org/mypackщоб повторно використовувати код в інших проектах. Якщо ви використовуєте libто внутрішні файли підтримки матимуть шлях імпорту , який свідчить про те, що myproj.org/lib/mysupport.

При побудові проекту використовуйте main/mypack, напр go build main/mypack. Якщо у вас є декілька виконуваних файлів, ви також можете відокремити ті, що не знаходяться mainбез створення окремих проектів. наприклад main/myfoo/myfoo.goі main/mybar/mybar.go.


14
Idomatic - використовувати cmd/nameOfMyExecutableпідкаталог для основного пакету (потрібно лише у тому cmd/…випадку, якщо у вас є кілька команд; див golang.org/x/tools/cmd. В іншому випадку звичайно поміняти його навколо і мати main.goна верхньому рівні). Як ви це зробите, go installви створите "головний" (або "main.exe") виконуваний файл. Крім того, ідіоматичним є використання internalпідкаталогу для підпакету, внутрішнього в пакеті / програмі, який не призначений для використання в іншому місці (очікується, що майбутні версії Go не примусять нікого іншого імпортуватиinternal пакунки, виконані таким чином).
Дейв C

21

Мені здається дуже корисним зрозуміти, як організувати код у Голанзі в цій главі http://www.golang-book.com/11 книги, написаної Калебом Докссі


13

Здається, не існує стандартного способу організації проектів Go, але https://golang.org/doc/code.html визначає найкращу практику для більшості проектів. Відповідь jdi хороша, але якщо ви використовуєте github або bitbucket, а також у вас є додаткові бібліотеки, вам слід створити таку структуру:

~/projects/
bin/
pkg/
src/
  github.com/
    username/
        mypack/
            foo.go
            bar.go
            mypack_test.go
        mylib/
            utillib.go
            utillib_test.go

Роблячи це таким чином, ви можете мати окреме сховище для mylib, яке можна використовувати для інших проектів, і його можна отримати за допомогою "go get". Ваш проект mypack може імпортувати вашу бібліотеку за допомогою "github.com/username/mylib". Для отримання додаткової інформації:

http://www.alexvictorchan.com/2014/11/06/go-project-structure/


6

Зберігайте файли в одному каталозі та використовуйте package mainу всіх файлах.

myproj/
   your-program/
      main.go
      lib.go

Потім запустіть:

~/myproj/your-program$ go build && ./your-program

Як це може працювати? Ваш main.go повинен бути основним пакетом; імовірно, що lib.go знаходиться в іншому пакеті, тоді інструмент "go" скаржиться, що не можна мати два пакети в одній папці.
I82Муч

1
@ I82Much OP запитує, як розділити один пакунок, основну програму, на багато файлів. lib.go знаходиться в цьому ж пакеті в цьому випадку.
Густав

Ах, дякую за роз’яснення.
I82Моч

@ Густав, у мене те саме питання. Здається, якщо я поставив пакунок main в lib.go, в main.go, я не можу викликати функції, визначені в lib.go.
Qian Chen

@ElgsQianChen Методи повинні бути загальнодоступними, починати слід з великої літери. Наприклад, MyMethod () або MyStruct {...}.
Густав

6

Давайте дослідимо, як go get repository_remote_urlкоманда управляє структурою проекту в $GOPATH. Якщо ми зробимо це, go get github.com/gohugoio/hugoвін буде клонувати репозиторій під

$ GOPATH / src / repository_remote / user_name / project_name


$ GOPATH / src / github.com/gohugoio/hugo

Це хороший спосіб створити свій початковий шлях до проекту . Тепер давайте дослідимо, які існують типи проектів та як їх внутрішні структури організовані. Усі гололанг-проекти в громаді можна віднести до категорії

  • Libraries (немає виконуваних двійкових файлів)
  • Single Project (містить лише 1 виконуваний двійковий файл)
  • Tooling Projects (містить кілька виконуваних двійкових файлів)

Як правило, файли проекту на голонг можна упакувати за будь-якими принципами дизайну, такими як DDD , POD

Більшість доступних проектів іде за цим дизайном, орієнтованим на пакет

Дизайн, орієнтований на пакунки, заохочує розробника зберігати реалізацію лише у власних пакетах, окрім /internalпакету, який вони не можуть спілкуватися один з одним


Бібліотеки

  • Такі проекти, як драйвери баз даних , qt можна помістити під цю категорію.
  • Деякі бібліотеки, такі як колір , тепер дотримуються плоскої структури без будь-яких інших пакетів.
  • Більшість цих бібліотечних проектів управляє пакетом, який називається внутрішнім .
  • /internal пакет в основному використовується для приховування реалізації від інших проектів.
  • Не має виконувані двійкові файли, так що немає файлів, що містяться в основний FUNC .

 ~/$GOPATH/
    bin/
    pkg/
    src/
      repository_remote/
        user_name/
            project_name/
              internal/
              other_pkg/

Єдиний проект

  • Проекти , такі як Гуго , etcd мають єдину основну FUNC в кореневому рівні і.
  • Мета - генерувати один єдиний двійковий код

Інструментальні проекти

  • Такі проекти, як kubernetes , go-ethereum мають кілька основних функцій , організованих під пакет, що називається cmd
  • cmd/ пакет управляє кількістю бінарних файлів (інструментів), які ми хочемо створити

 ~/$GOPATH/
    bin/
    pkg/
    src/
      repository_remote/
        user_name/
            project_name/
              cmd/
                binary_one/
                   main.go
                binary_two/
                   main.go
                binary_three/
                   main.go
              other_pkg/
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.