Organizowanie projektu Go z wieloma plikami [zamknięte]


238

Uwaga: to pytanie jest związane z tym , ale dwa lata to bardzo długi czas w historii Go.

Jaki jest standardowy sposób organizacji projektu Go podczas programowania?

Mój projekt to jeden pakiet mypack, więc chyba wszystkie pliki .go umieściłem w mypackkatalogu.

Ale potem chciałbym to przetestować podczas programowania, więc potrzebuję przynajmniej pliku deklarującego mainpakiet, aby móc to zrobićgo run trypack.go

Jak mam to zorganizować? Czy muszę to robić za go install mypackkażdym razem, gdy chcę to wypróbować?


14
Ten krótki zrzut ekranu jest niesamowity: youtube.com/watch?v=XCsL89YtqCs
Matt

To kolejny pomocny link do zrozumienia, jak zorganizować projekt z pakietami. Myślę, że łatwiejsze do naśladowania niż oficjalne Jak napisać kod Go.
IamNaN

W przypadku nowego systemu modułów Go ta odpowiedź obejmuje strukturę modułów, organizowanie pakietów w module, czy mieć wiele modułów w jednym repozytorium itp. W końcu oficjalny dokument wprowadzający „Jak napisać kod Go” zostanie zaktualizowany dla modułów , ale tak się jeszcze nie stało. (Jeśli jesteś nowy w Go i nowy w Go, nadal warto przeczytać ten dokument „Jak napisać Go Go Code”, zanim przeczytasz więcej o modułach, biorąc pod uwagę, że znaczna część dokumentacji modułów zakłada znajomość GOPATH).
typowy 182

Odpowiedzi:


171

Polecam przejrzenie tej strony na temat pisania kodu Go

Dokumentuje zarówno sposób przyjaznej strukturyzacji projektu go build, jak i pisanie testów. Testy nie muszą być cmd przy użyciu mainpakietu. Mogą być po prostu nazwanymi funkcjami TestX jako część każdego pakietu, a następnie go testje odkryją.

Struktura sugerowana w tym łączu w twoim pytaniu jest nieco nieaktualna, teraz wraz z wydaniem Go 1. Nie będziesz już musiał umieszczać pkgkatalogu pod src. Jedyne 3 katalogi związane ze specyfikacją to 3 w katalogu głównym GOPATH: bin, pkg, src. Pod src możesz po prostu umieścić swój projekt mypack, a pod nim wszystkie twoje pliki .go, w tym mypack_test.go

go build następnie wbuduje się w pkg i bin poziom root.

Twój GOPATH może wyglądać następująco:

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

export GOPATH=$HOME/projects

$ go build mypack
$ go test mypack

Aktualizacja: od> = Go 1.11, system modułowy jest teraz standardową częścią oprzyrządowania, a koncepcja GOPATH jest już prawie przestarzała.


26
Podczas eksportowania zmiennych użyj $ HOME zamiast ~.
Johan S

6
Dlaczego $ HOME jest zalecane zamiast ~ podczas eksportowania zmiennych?
425nesp

8
Ponieważ ~ nie jest zmienną, tylko aliasem.
Pih

6
@ 425nesp Johan się myli - nie jest. Powłoki różnią się, ale bash rozszerza się ~podczas ustawiania zmiennych środowiskowych , podobnie jak na przykład powłoka bourne busybox. Spróbuj sam: export BOB=~ && env | grep ^BOBprzyniesieBOB=/your/homedir
Austin Adams

1
$HOMEpracuje wtedy w większej ilości pocisków ~, na przykład infish
hoijui

60

jdi ma właściwe informacje dotyczące korzystania z GOPATH. Dodałbym, że jeśli zamierzasz mieć również plik binarny, możesz chcieć dodać jeden dodatkowy poziom do katalogów.

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

uruchomiony go build myproj/mypackzbuduje mypackpakiet wraz z jego zależnościami działa go build myproj/myappzbuduje myappbinarny wraz z nim w zależności, która prawdopodobnie zawiera się mypackbiblioteka.


Miałoby to oczywiście sens, gdyby rzeczywiście miał główne polecenie cmd. Wydawało się, że właśnie tworzy pakiet biblioteczny.
jdi

50

Przebadałem wiele projektów Go i istnieje spora różnorodność. Możesz powiedzieć, kto pochodzi z C, a kto z Javy, ponieważ pierwszy zrzut prawie wszystko w katalogu głównym projektów w mainpakiecie, a drugi zwykle umieszcza wszystko wsrc katalogu. Jednak żadne nie jest optymalne. Każda z nich ma konsekwencje, ponieważ wpływa na ścieżki importu i sposób, w jaki inni mogą z nich korzystać ponownie.

Aby uzyskać najlepsze wyniki, opracowałem następujące podejście.

myproj/
  main/
    mypack.go
  mypack.go

Gdzie mypack.gojest package mypacki main/mypack.gojest (oczywiście) package main.

Jeśli potrzebujesz dodatkowych plików pomocniczych, masz dwie możliwości. Albo zachowaj je wszystkie w katalogu głównym, albo umieść prywatne pliki pomocy w libpodkatalogu. Na przykład

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

Lub

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

Pliki umieść w libkatalogu tylko wtedy, gdy nie są przeznaczone do zaimportowania przez inny projekt. Innymi słowy, jeśli są to prywatne pliki wsparcia. Taki jest pomysł posiadanialib - w celu oddzielenia interfejsów publicznych od prywatnych.

Robienie tego w ten sposób da ci dobrą ścieżkę importu, myproj.org/mypackaby ponownie wykorzystać kod w innych projektach. Jeśli używasz libwtedy wewnętrzne pliki pomocnicze będzie miał ścieżkę importu, który wskazuje, że myproj.org/lib/mysupport.

Budując projekt, użyj main/mypacknp go build main/mypack. Jeśli masz więcej niż jeden plik wykonywalny, możesz również oddzielić je od siebie mainbez konieczności tworzenia osobnych projektów. np . main/myfoo/myfoo.goi main/mybar/mybar.go.


14
Idomatic ma użyć cmd/nameOfMyExecutablepodkatalogu dla pakietu głównego (potrzebne tylko, cmd/…jeśli masz wiele poleceń; zobacz golang.org/x/tools/cmd; w przeciwnym razie często jest to zamieniane i ma to main.gona najwyższym poziomie). W ten sposób go installutworzysz plik wykonywalny „main” (lub „main.exe”). Ponadto, idiomatic ma używać internalpodkatalogu dla sub-pakietu wewnętrznego dla pakietu / programu, który nie powinien być używany gdzie indziej (oczekuje się, że przyszłe wersje Go nie będą wymuszać, aby nikt inny importował internalpakiety w ten sposób).
Dave C


13

Wydaje się, że nie ma standardowego sposobu organizowania projektów Go, ale https://golang.org/doc/code.html określa najlepszą praktykę dla większości projektów. Odpowiedź jdi jest dobra, ale jeśli używasz github lub bitbucket i masz także dodatkowe biblioteki, powinieneś utworzyć następującą strukturę:

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

Robiąc to w ten sposób, możesz mieć osobne repozytorium dla mylib, które może być używane do innych projektów i może być odzyskane przez „go get”. Twój projekt mypack może zaimportować bibliotekę za pomocą „github.com/username/mylib”. Po więcej informacji:

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


6

Przechowuj pliki w tym samym katalogu i używaj package mainwe wszystkich plikach.

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

Następnie uruchomić:

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

Jak to może działać? Twoje main.go musi być pakietem głównym; prawdopodobnie lib.go jest w innym pakiecie, a następnie narzędzie go skarży się, że nie możesz mieć dwóch pakietów w jednym folderze.
I82 Wiele

1
@ I82 Wiele OP prosi o podzielenie jednego pakietu, programu głównego, na wiele plików. lib.go znajduje się w tym samym pakiecie.
Gustav,

Ach, dziękuję za wyjaśnienia.
I82 Wiele

@Gustav, mam to samo pytanie. Wygląda na to, że jeśli umieszczę pakiet main w lib.go, w main.go, nie będę mógł wywoływać funkcji zdefiniowanych w lib.go.
Qian Chen

@ElgsQianChen Metody muszą być publiczne, zaczynają się od dużej litery. Np. MyMethod () lub MyStruct {...}.
Gustav

6

Zobaczmy, w jaki sposób go get repository_remote_urlpolecenie zarządza strukturą projektu $GOPATH. Jeśli to zrobimy go get github.com/gohugoio/hugo, sklonuje repozytorium pod

$ GOPATH / src / repository_remote / nazwa_użytkownika / nazwa_projektu


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

To dobry sposób na utworzenie początkowej ścieżki projektu . Teraz zbadajmy, jakie są typy projektów i jak są zorganizowane ich wewnętrzne struktury. Wszystkie projekty golang w społeczności można podzielić na kategorie

  • Libraries (brak wykonywalnych plików binarnych)
  • Single Project (zawiera tylko 1 plik wykonywalny)
  • Tooling Projects (zawiera wiele wykonywalnych plików binarnych)

Zasadniczo pliki projektów golang można spakować zgodnie z dowolnymi zasadami projektowania, takimi jak DDD , POD

Większość dostępnych projektów go jest zgodna z tym pakietowym projektem

Projektowanie zorientowane na pakiet zachęca dewelopera do utrzymywania implementacji tylko w swoich własnych pakietach, innych niż /internalpakiet, którego te pakiety nie mogą się ze sobą komunikować


Biblioteki

  • Projekty takie jak sterowniki baz danych , qt można umieścić w tej kategorii.
  • Niektóre biblioteki, takie jak kolor , teraz płaską strukturę bez żadnych innych pakietów.
  • Większość tych projektów bibliotecznych zarządza pakietem zwanym wewnętrznym .
  • /internal Pakiet służy głównie do ukrywania implementacji przed innymi projektami.
  • Nie ma żadnych wykonywalnych plików binarnych, więc żadne pliki nie zawierają głównego func .

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

Pojedynczy projekt

  • Projekty takie jak hugo , etcd mają jeden główną na poziomie root i.
  • Celem jest wygenerowanie jednego pliku binarnego

Projekty narzędzi

  • Projekty takie jak kubernetes , go-ethereum mają wiele głównych funkcji zorganizowanych w pakiecie o nazwie cmd
  • cmd/ pakiet zarządza liczbą plików binarnych (narzędzi), które chcemy zbudować

 ~/$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/
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.