Organisieren eines Go-Projekts mit mehreren Dateien [geschlossen]

237

Hinweis: Diese Frage bezieht sich auf diese , aber zwei Jahre sind eine sehr lange Zeit in der Go-Geschichte.

Was ist die Standardmethode, um ein Go-Projekt während der Entwicklung zu organisieren?

Mein Projekt ist ein einzelnes Paket mypack, also habe ich wohl alle .go-Dateien in einem mypackVerzeichnis abgelegt .

Aber dann möchte ich es während der Entwicklung testen, damit ich mindestens eine Datei benötige, die das mainPaket deklariert , damit ich es tun kanngo run trypack.go

Wie soll ich das organisieren? Muss ich go install mypackjedes Mal tun, wenn ich es versuchen möchte?

Blacksad
quelle
14
Dieser kurze Screencast ist fantastisch: youtube.com/watch?v=XCsL89YtqCs
Matt
Dies ist ein weiterer hilfreicher Link, um zu verstehen, wie ein Projekt mit Paketen organisiert wird. Einfacher zu befolgen als der offizielle How to Write go Code, denke ich.
IamNaN
Für das neue Go- Modulsystem behandelt diese Antwort die Modulstruktur, das Anordnen von Paketen innerhalb eines Moduls, ob mehrere Module in einem Repository vorhanden sein sollen oder nicht usw. Schließlich wird das offizielle Intro-Dokument "How to Write Go Code" für Module aktualisiert , aber das ist noch nicht passiert. (Wenn Sie mit Go- und Go-Modulen noch nicht vertraut sind, sollten Sie das Dokument "How to Write Go Code" lesen, bevor Sie mehr über Module lesen, da ein Großteil der Moduldokumentation von GOPATH ausgeht.)
typisch182

Antworten:

171

Ich würde empfehlen, diese Seite unter Schreiben von Go-Code zu lesen

Es dokumentiert sowohl die go buildfreundliche Strukturierung Ihres Projekts als auch das Schreiben von Tests. Tests müssen mit dem mainPaket kein cmd sein . Sie können einfach TestX-benannte Funktionen als Teil jedes Pakets sein und go testwerden sie dann entdecken.

Die in diesem Link in Ihrer Frage vorgeschlagene Struktur ist etwas veraltet, jetzt mit der Veröffentlichung von Go 1. Sie müssten kein pkgVerzeichnis mehr unter platzieren src. Die einzigen 3 spezifikationsbezogenen Verzeichnisse sind die 3 im Stammverzeichnis Ihres GOPATH: bin, pkg, src. Unter src können Sie einfach Ihr Projekt platzieren mypack, und darunter befinden sich alle Ihre .go-Dateien, einschließlich mypack_test.go

go build wird dann in die Root-Ebene pkg und bin bauen.

Ihr GOPATH könnte also so aussehen:

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

export GOPATH=$HOME/projects

$ go build mypack
$ go test mypack

Update: wie von> = Go 1.11, das Modulsystem ist jetzt ein Standardteil des Werkzeugs und das GOPATH Konzept ist in der Nähe obsolet zu werden.

jdi
quelle
26
Verwenden Sie beim Exportieren von Variablen $ HOME anstelle von ~.
Johan S
6
Warum wird $ HOME beim Exportieren von Variablen gegenüber ~ empfohlen?
425nesp
8
Weil ~ keine Variable ist, sondern nur ein Alias.
Pih
6
@ 425nesp Johan irrt sich - es ist nicht. Shells variieren, aber Bash wird ~beim Festlegen von Umgebungsvariablen erweitert , ebenso wie beispielsweise die Busybox-Bourne-Shell. Probieren Sie es aus: export BOB=~ && env | grep ^BOBwird nachgebenBOB=/your/homedir
Austin Adams
1
$HOMEarbeitet dann in mehr Muscheln ~, zum Beispiel infish
hoijui
60

jdi hat die richtigen Informationen bezüglich der Verwendung von GOPATH. Ich würde hinzufügen, dass Sie, wenn Sie auch eine Binärdatei haben möchten, möglicherweise eine zusätzliche Ebene zu den Verzeichnissen hinzufügen möchten.

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

Durch Ausführen go build myproj/mypackwird das mypackPaket zusammen mit den Abhängigkeiten erstellt. Durch Ausführen go build myproj/myappwird die myappBinärdatei zusammen mit den Abhängigkeiten erstellt, die wahrscheinlich die mypackBibliothek enthalten.

Jeremy Wall
quelle
Dies wäre natürlich sinnvoll, wenn er tatsächlich einen Haupt-Cmd hätte. Anscheinend erstellt er gerade ein Bibliothekspaket.
JDI
49

Ich habe eine Reihe von Go-Projekten studiert und es gibt einiges an Abwechslung. Sie können feststellen, wer von C und wer von Java kommt, da der erstere Speicherauszug fast alles im Stammverzeichnis des Projekts in einem mainPaket enthält und der letztere dazu neigt, alles in ein srcVerzeichnis zu stellen. Beides ist jedoch nicht optimal. Beide haben Konsequenzen, da sie sich auf Importpfade auswirken und darauf, wie andere sie wiederverwenden können.

Um die besten Ergebnisse zu erzielen, habe ich den folgenden Ansatz ausgearbeitet.

myproj/
  main/
    mypack.go
  mypack.go

Wo mypack.goist package mypackund main/mypack.goist (offensichtlich) package main.

Wenn Sie zusätzliche Unterstützungsdateien benötigen, haben Sie zwei Möglichkeiten. Bewahren Sie sie entweder alle im Stammverzeichnis auf oder speichern Sie private Supportdateien in einem libUnterverzeichnis. Z.B

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

Oder

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

Legen Sie die Dateien nur in einem libVerzeichnis ab, wenn sie nicht von einem anderen Projekt importiert werden sollen. Mit anderen Worten, wenn es sich um private Supportdateien handelt. Das ist die Idee dahinter, liböffentliche von privaten Schnittstellen zu trennen.

Wenn Sie die Dinge auf diese Weise myproj.org/mypackausführen , erhalten Sie einen schönen Importpfad, um den Code in anderen Projekten wiederzuverwenden. Wenn Sie verwenden, haben libinterne Support-Dateien einen Importpfad, der darauf hinweist myproj.org/lib/mysupport.

Verwenden Sie beim Erstellen des Projekts main/mypackz go build main/mypack. Wenn Sie mehr als eine ausführbare Datei haben, können Sie diese auch unter trennen, mainohne separate Projekte erstellen zu müssen. zB main/myfoo/myfoo.gound main/mybar/mybar.go.

trans
quelle
14
Idomatisch ist die Verwendung eines cmd/nameOfMyExecutableUnterverzeichnisses für das Hauptpaket (nur erforderlich, cmd/…wenn Sie mehrere Befehle haben; siehe golang.org/x/tools/cmd; ansonsten ist es üblich, es auszutauschen und main.goauf der obersten Ebene zu haben). So wie Sie es haben, go installwird eine ausführbare Datei "main" (oder "main.exe") erstellt. Idiomatisch ist es auch, ein internalUnterverzeichnis für ein Unterpaket innerhalb des Pakets / Programms zu verwenden, das nicht für andere Zwecke verwendet werden soll (es wird erwartet, dass zukünftige Versionen von Go niemanden dazu zwingen werden, internalPakete auf diese Weise zu importieren ).
Dave C
21

Ich finde es sehr nützlich zu verstehen, wie man Code in Golang in diesem Kapitel http://www.golang-book.com/11 des Buches von Caleb Doxsey organisiert

edap
quelle
13

Es scheint keine Standardmethode zum Organisieren von Go-Projekten zu geben, aber https://golang.org/doc/code.html gibt eine bewährte Methode für die meisten Projekte an. Die Antwort von jdi ist gut, aber wenn Sie Github oder Bitbucket verwenden und zusätzliche Bibliotheken haben, sollten Sie die folgende Struktur erstellen:

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

Auf diese Weise können Sie ein separates Repository für mylib einrichten, das für andere Projekte verwendet und über "go get" abgerufen werden kann. Ihr mypack-Projekt kann Ihre Bibliothek über "github.com/username/mylib" importieren. Für mehr Informationen:

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

alexdotc
quelle
6

Bewahren Sie die Dateien im selben Verzeichnis auf und verwenden Sie sie package mainin allen Dateien.

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

Dann renne:

~/myproj/your-program$ go build && ./your-program
Gustav
quelle
Wie kann das funktionieren? Ihre main.go muss das Paket main sein. vermutlich befindet sich lib.go in einem anderen Paket, dann beschwert sich das go-Tool, dass Sie nicht zwei Pakete in einem einzigen Ordner haben können.
I82Much
1
@ I82Much OP fragt, wie ein Paket, das Hauptprogramm, in viele Dateien aufgeteilt werden soll. lib.go befindet sich in diesem Fall im selben Paket.
Gustav
Ah danke für die Klarstellung.
I82Much
@Gustav, ich habe die gleiche Frage. Es scheint, wenn ich das Paket main in lib.go, in main.go platziere, kann ich keine in lib.go definierten Funktionen aufrufen.
Qian Chen
@ElgsQianChen Die Methoden müssen öffentlich sein, sie müssen mit einem Großbuchstaben beginnen. ZB MyMethod () oder MyStruct {...}.
Gustav
6

Lassen Sie uns untersuchen, wie der go get repository_remote_urlBefehl die Projektstruktur unter verwaltet $GOPATH. Wenn wir ago get github.com/gohugoio/hugo wird das Repository unter geklont

$ GOPATH / src / repository_remote / benutzername / projektname


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

Dies ist eine gute Möglichkeit, Ihren ersten Projektpfad zu erstellen . Lassen Sie uns nun untersuchen, welche Projekttypen es gibt und wie ihre inneren Strukturen organisiert sind. Alle Golang-Projekte in der Community können unter kategorisiert werden

  • Libraries (keine ausführbaren Binärdateien)
  • Single Project (enthält nur 1 ausführbare Binärdatei)
  • Tooling Projects (enthält mehrere ausführbare Binärdateien)

Im Allgemeinen können Golang-Projektdateien nach beliebigen Entwurfsprinzipien wie DDD , POD gepackt werden

Die meisten verfügbaren Go-Projekte folgen diesem paketorientierten Design

Paketorientiertes Design ermutigt den Entwickler, die Implementierung nur in seinen eigenen Paketen zu belassen, außer in dem /internalPaket, das diese Pakete nicht miteinander kommunizieren können


Bibliotheken

  • Projekte wie Datenbanktreiber , qt in diese Kategorie .
  • Einige Bibliotheken wie Farbe , jetzt folgt eine flache Struktur ohne weitere Pakete.
  • Die meisten dieser Bibliotheksprojekte verwalten ein Paket namens intern .
  • /internal Paket wird hauptsächlich verwendet, um die Implementierung vor anderen Projekten zu verbergen.
  • Haben keine ausführbare Binärdateien, so dass keine Dateien, die die enthält Haupt Func .

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

Einzelprojekt

  • Projekte wie hugo , etcd haben eine einzige Hauptfunktion in root level und.
  • Ziel ist es, eine einzelne Binärdatei zu generieren

Werkzeugprojekte

  • Projekte wie kubernetes , go-ethereum haben mehrere Hauptfunktionen, die unter einem Paket namens cmd organisiert sind
  • cmd/ Paket verwaltet die Anzahl der Binärdateien (Tools), die wir erstellen möchten

 ~/$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/
Noelyahan
quelle