Organizzazione di un progetto Go a più file [chiuso]


238

Nota: questa domanda è collegata a questa , ma due anni sono molto lunghi nella storia di Go.

Qual è il modo standard di organizzare un progetto Go durante lo sviluppo?

Il mio progetto è un singolo pacchetto mypack, quindi immagino di aver inserito tutti i file .go in una mypackdirectory.

Ma poi, vorrei testarlo durante lo sviluppo, quindi ho bisogno di almeno un file che dichiari il mainpacchetto, in modo che io possa farlogo run trypack.go

Come dovrei organizzarlo? Devo farlo go install mypackogni volta che voglio provarlo?


14
Questo breve screencast è fantastico: youtube.com/watch?v=XCsL89YtqCs
Matt,

Questo è un altro link utile per capire come organizzare un progetto con pacchetti. Più facile da seguire rispetto al codice How to Writing ufficiale, credo.
IamNaN,

Per il nuovo sistema di moduli Go, questa risposta copre la struttura del modulo, l'organizzazione dei pacchetti all'interno di un modulo, se disporre o meno di più moduli in un singolo repository, ecc. Alla fine, il documento introduttivo "How to Write Go Code" ufficiale verrà aggiornato per i moduli , ma non è ancora successo. (Se sei un nuovo utente di Go e un nuovo modulo Go, vale comunque la pena leggere il documento "Come scrivere il codice Go" prima di leggere di più sui moduli, dato che gran parte della documentazione dei moduli assume familiarità con GOPATH).
tipico182

Risposte:


171

Consiglierei di rivedere questa pagina su Come scrivere il codice Go

Documenta sia come strutturare il progetto in go buildmodo amichevole, sia come scrivere test. Non è necessario che i test siano un cmd usando il mainpacchetto. Possono semplicemente essere funzioni denominate TestX come parte di ciascun pacchetto, quindi go testle scopriranno.

La struttura suggerita in quel link nella tua domanda è un po 'datata, ora con il rilascio di Go 1. Non dovrai più posizionare una pkgdirectory sotto src. Le uniche 3 directory relative alle specifiche sono le 3 nella radice di GOPATH: bin, pkg, src. Sotto src, puoi semplicemente posizionare il tuo progetto mypacke sotto ci sono tutti i tuoi file .go incluso mypack_test.go

go build verrà quindi integrato nel livello radice pkg e bin.

Quindi il tuo GOPATH potrebbe assomigliare a questo:

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

export GOPATH=$HOME/projects

$ go build mypack
$ go test mypack

Aggiornamento: a partire da> = Go 1.11, il sistema del modulo è ora una parte standard degli strumenti e il concetto GOPATH sta per diventare obsoleto.


26
Utilizzare $ HOME invece di ~ quando si esportano variabili.
Johan S,

6
Perché $ HOME è consigliato su ~ quando si esportano variabili?
425nesp

8
Perché ~ non è una variabile, solo un alias.
Pih,

6
@ 425nesp Johan si sbaglia - non lo è. Le shell variano, ma bash si espande ~quando si impostano le variabili ambientali , così come la shell bourne di busybox, per esempio. Provalo tu stesso: export BOB=~ && env | grep ^BOBcederaiBOB=/your/homedir
Austin Adams il

1
$HOMEfunziona in più shell quindi ~, ad esempio infish
hoijui il

60

jdi ha le giuste informazioni sull'uso di GOPATH. Aggiungerei che se hai intenzione di avere anche un binario potresti voler aggiungere un ulteriore livello alle directory.

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

running go build myproj/mypackcostruirà il mypackpacchetto insieme alle sue dipendenze running go build myproj/myappcostruirà il myappbinario insieme alle sue dipendenze che probabilmente include la mypacklibreria.


Ciò avrebbe senso, ovviamente, se avesse effettivamente avuto un cmd principale. Sembrava che stesse solo creando un pacchetto di librerie.
jdi

50

Ho studiato una serie di progetti Go e ci sono molte variazioni. Puoi dire chi proviene da C e chi proviene da Java, poiché il primo dump praticamente tutto nella directory root dei progetti in un mainpacchetto, e il secondo tende a mettere tutto in una srcdirectory. Nessuno dei due è comunque ottimale. Ognuno ha conseguenze perché influenzano i percorsi di importazione e come gli altri possono riutilizzarli.

Per ottenere i migliori risultati ho elaborato il seguente approccio.

myproj/
  main/
    mypack.go
  mypack.go

Dove mypack.goè package mypacked main/mypack.goè (ovviamente) package main.

Se hai bisogno di ulteriori file di supporto hai due possibilità. Conservali tutti nella directory principale o inserisci i file di supporto privati in una libsottodirectory. Per esempio

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

O

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

Metti i file in una libdirectory solo se non sono destinati ad essere importati da un altro progetto. In altre parole, se sono file di supporto privati . Questa è l'idea alla base dell'avere - di libseparare le interfacce pubbliche da quelle private.

Fare le cose in questo modo ti darà un bel percorso di importazione, myproj.org/mypackper riutilizzare il codice in altri progetti. Se si utilizza, libi file di supporto interni avranno un percorso di importazione indicativo di ciò myproj.org/lib/mysupport,.

Quando si costruisce il progetto, utilizzare main/mypack, ad es go build main/mypack. Se disponi di più di un eseguibile, puoi anche separarli mainsenza dover creare progetti separati. eg main/myfoo/myfoo.goe main/mybar/mybar.go.


14
Idomatic è usare una cmd/nameOfMyExecutablesottodirectory per il pacchetto principale (è necessario solo cmd/…se si hanno più comandi; vedere golang.org/x/tools/cmd; altrimenti è comune scambiarlo e farlo main.goal livello più alto). Il modo in cui lo go installcreerai creerà un eseguibile "main" (o "main.exe"). Inoltre, idiomatico è usare una internalsottodirectory per un sotto-pacchetto interno al pacchetto / programma che non è pensato per essere usato altrove (si prevede che le versioni future di Go non imporranno a nessun altro importare internalpacchetti fatti in questo modo).
Dave C,


13

Non sembra esserci un modo standard di organizzare i progetti Go ma https://golang.org/doc/code.html specifica una best practice per la maggior parte dei progetti. La risposta di jdi è buona ma se usi github o bitbucket e hai anche librerie aggiuntive, dovresti creare la seguente struttura:

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

In questo modo, è possibile disporre di un repository separato per mylib che può essere utilizzato per altri progetti e può essere recuperato da "go get". Il tuo progetto mypack può importare la tua libreria usando "github.com/username/mylib". Per maggiori informazioni:

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


6

Conservare i file nella stessa directory e utilizzarli package mainin tutti i file.

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

Quindi eseguire:

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

1
Come può funzionare? Il tuo main.go deve essere il pacchetto principale; presumibilmente lib.go si trova in un pacchetto diverso, quindi lo strumento go si lamenta che non è possibile avere due pacchetti in una singola cartella.
I82 Molto

1
@ I82 Molto OP chiede come dividere un pacchetto, il programma principale, in molti file. lib.go è nello stesso pacchetto in questo caso.
Gustav,

Ah grazie per il chiarimento.
I82 Molto

@Gustav, ho la stessa domanda. Sembra che se inserisco il pacchetto main in lib.go, in main.go, non riesco a chiamare le funzioni definite in lib.go.
Qian Chen,

@ElgsQianChen I metodi devono essere pubblici, deve iniziare con una lettera maiuscola. Ad esempio MyMethod () o MyStruct {...}.
Gustav,

6

Esploriamo come il go get repository_remote_urlcomando gestisce la struttura del progetto in $GOPATH. Se lo facciamo go get github.com/gohugoio/hugo, clonerà il repository in

$ GOPATH / src / repository_remote / nome_utente / nome_progetto


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

Questo è un bel modo per creare il percorso iniziale del progetto . Ora esploriamo quali sono i tipi di progetto là fuori e come sono organizzate le loro strutture interne. Tutti i progetti Golang nella comunità possono essere classificati sotto

  • Libraries (nessun file binario eseguibile)
  • Single Project (contiene solo 1 file binario eseguibile)
  • Tooling Projects (contiene più file binari eseguibili)

Generalmente i file di progetto Golang possono essere impacchettati secondo qualsiasi principio di progettazione come DDD , POD

La maggior parte dei progetti go disponibili segue questo Design orientato al pacchetto

Il design orientato ai pacchetti incoraggia lo sviluppatore a mantenere l'implementazione solo all'interno dei propri pacchetti, oltre al /internalpacchetto che questi pacchetti non possono comunicare tra loro


biblioteche

  • Progetti come driver di database , qt possono essere inseriti in questa categoria.
  • Alcune librerie come color , ora seguono una struttura piatta senza altri pacchetti.
  • La maggior parte di questi progetti di biblioteche gestisce un pacchetto chiamato interno .
  • /internal il pacchetto viene utilizzato principalmente per nascondere l'implementazione ad altri progetti.
  • Non ha binari eseguibili, quindi nessun file che contiene la funzione principale .

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

Progetto unico

  • Progetti come hugo , etcd hanno un'unica funzione principale a livello di root e.
  • L'obiettivo è generare un singolo binario

Progetti di utensili

  • Progetti come kubernetes , go-ethereum hanno molteplici funzioni principali organizzate in un pacchetto chiamato cmd
  • cmd/ Il pacchetto gestisce il numero di file binari (strumenti) che vogliamo costruire

 ~/$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/
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.