Organizar un proyecto Go de múltiples archivos [cerrado]

238

Nota: esta pregunta está relacionada con esta , pero dos años es mucho tiempo en la historia de Go.

¿Cuál es la forma estándar de organizar un proyecto Go durante el desarrollo?

Mi proyecto es un paquete único mypack, así que supongo que pongo todos los archivos .go en un mypackdirectorio.

Pero luego, me gustaría probarlo durante el desarrollo, por lo que necesito al menos un archivo que declare el mainpaquete, para que pueda hacergo run trypack.go

¿Cómo debo organizar esto? ¿Debo hacerlo go install mypackcada vez que quiera probarlo?

Blacksad
fuente
14
Este breve screencast es impresionante: youtube.com/watch?v=XCsL89YtqCs
Matt
Este es otro enlace útil para comprender cómo organizar un proyecto con paquetes. Más fácil de seguir que el código oficial Cómo escribir go creo.
IamNaN
Para el nuevo sistema de módulos Go, esta respuesta cubre la estructura del módulo, la organización de paquetes dentro de un módulo, si se tienen o no múltiples módulos en un único repositorio, etc. Eventualmente, el documento de introducción oficial "Cómo escribir Go Code" se actualizará para los módulos , pero eso aún no ha sucedido. (Si es nuevo en los módulos Go y nuevos en Go, vale la pena leer el documento "Cómo escribir el código Go" antes de leer más sobre los módulos, dado que gran parte de la documentación de los módulos supone estar familiarizado con GOPATH).
típico182

Respuestas:

171

Recomendaría revisar esta página sobre Cómo escribir el código Go

Documenta cómo estructurar su proyecto de go buildmanera amigable y también cómo escribir pruebas. Las pruebas no necesitan ser un cmd usando el mainpaquete. Simplemente pueden ser funciones con nombre TestX como parte de cada paquete, y luego las go testdescubrirán.

La estructura sugerida en ese enlace en su pregunta está un poco desactualizada, ahora con el lanzamiento de Go 1. Ya no necesitaría colocar un pkgdirectorio debajo src. Los únicos 3 directorios relacionados con las especificaciones son los 3 en la raíz de su GOPATH: bin, pkg, src. Debajo de src, simplemente puede colocar su proyecto mypack, y debajo de eso están todos sus archivos .go, incluido mypack_test.go

go build luego se integrará en el nivel raíz pkg y bin.

Entonces su GOPATH podría verse así:

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

export GOPATH=$HOME/projects

$ go build mypack
$ go test mypack

Actualización: a partir de> = Go 1.11, el sistema Módulo ahora es una parte estándar de las herramientas y el concepto GOPATH está a punto de quedar obsoleto.

jdi
fuente
26
Use $ HOME en lugar de ~ al exportar variables.
Johan S
66
¿Por qué se recomienda $ HOME sobre ~ al exportar variables?
425nesp
8
Porque ~ no es una variable, solo un alias.
Pih
66
@ 425nesp Johan se equivoca, no lo es. Los shells varían, pero bash se expande ~al establecer variables ambientales , y también lo hace el shell de bourne busybox, por ejemplo. Pruébelo usted mismo: export BOB=~ && env | grep ^BOBcederáBOB=/your/homedir
Austin Adams
1
$HOMEtrabaja en más conchas entonces ~, por ejemplo, enfish
hoijui
60

jdi tiene la información correcta sobre el uso de GOPATH. Agregaría que si también tiene la intención de tener un binario, es posible que desee agregar un nivel adicional a los directorios.

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

running go build myproj/mypackconstruirá el mypackpaquete junto con sus dependencias running ejecutará go build myproj/myappel myappbinario junto con sus dependencias, lo que probablemente incluye la mypackbiblioteca.

Jeremy Wall
fuente
Esto tendría sentido, por supuesto, si realmente tuviera un cmd principal. Parecía que solo estaba creando un paquete de biblioteca.
jdi
50

He estudiado varios proyectos de Go y hay bastante variación. Puede saber quién viene de C y quién viene de Java, ya que el primero voltea casi todo en el directorio raíz de proyectos en un mainpaquete, y el segundo tiende a colocar todo en un srcdirectorio. Sin embargo, ninguno es óptimo. Cada uno tiene consecuencias porque afectan las rutas de importación y cómo otros pueden reutilizarlas.

Para obtener los mejores resultados, elaboré el siguiente enfoque.

myproj/
  main/
    mypack.go
  mypack.go

Dónde mypack.goestá package mypacky main/mypack.goestá (obviamente) package main.

Si necesita archivos de soporte adicionales, tiene dos opciones. Manténgalos todos en el directorio raíz o coloque archivos de soporte privados en un libsubdirectorio. P.ej

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

Solo coloque los archivos en un libdirectorio si no están destinados a ser importados por otro proyecto. En otras palabras, si son archivos de soporte privados . Esa es la idea detrás de tener lib--para separar las interfaces públicas de las privadas.

Hacer las cosas de esta manera le dará una buena ruta de importación, myproj.org/mypackpara reutilizar el código en otros proyectos. Si lo usa lib, los archivos de soporte interno tendrán una ruta de importación que es indicativa de eso myproj.org/lib/mysupport,.

Al construir el proyecto, use main/mypack, por ejemplo go build main/mypack. Si tiene más de un ejecutable, también puede separarlos mainsin tener que crear proyectos separados. por ejemplo main/myfoo/myfoo.goy main/mybar/mybar.go.

trans
fuente
14
Idomatic es usar un cmd/nameOfMyExecutablesubdirectorio para el paquete principal (solo es necesario cmd/…si tiene varios comandos; vea golang.org/x/tools/cmd; de lo contrario, es común intercambiarlo y tenerlo main.goen el nivel superior). La forma en que lo go installtenga creará un ejecutable "main" (o "main.exe"). Además, lo idiomático es usar un internalsubdirectorio para un subpaquete interno del paquete / programa que no debe usarse en otro lugar (se espera que las futuras versiones de Go no obliguen a nadie más a importar internalpaquetes hechos de esta manera).
Dave C
13

No parece haber una forma estándar de organizar proyectos de Go, pero https://golang.org/doc/code.html especifica una mejor práctica para la mayoría de los proyectos. La respuesta de jdi es buena, pero si usa github o bitbucket y también tiene bibliotecas adicionales, debe crear la siguiente estructura:

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

Al hacerlo de esta manera, puede tener un repositorio separado para mylib que puede usarse para otros proyectos y puede recuperarse mediante "ir a buscar". Su proyecto mypack puede importar su biblioteca usando "github.com/username/mylib". Para más información:

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

alexdotc
fuente
6

Mantenga los archivos en el mismo directorio y úselos package mainen todos los archivos.

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

Entonces corre:

~/myproj/your-program$ go build && ./your-program
Gustav
fuente
1
¿Cómo puede funcionar esto? Su main.go debe ser el paquete main; presumiblemente lib.go está en un paquete diferente, entonces la herramienta go se queja de que no puede tener dos paquetes en una sola carpeta.
I82Mucho
1
@ I82Much OP pregunta cómo dividir un paquete, el programa principal, en muchos archivos. lib.go está en el mismo paquete en este caso.
Gustav
Ah, gracias por la aclaración.
I82Mucho
@Gustav, tengo la misma pregunta. Parece que si pongo el paquete main en lib.go, en main.go, no puedo llamar a las funciones definidas en lib.go.
Qian Chen
@ElgsQianChen Los métodos deben ser públicos, deben comenzar con una letra mayúscula. Por ejemplo, MyMethod () o MyStruct {...}.
Gustav
6

Exploremos cómo el go get repository_remote_urlcomando gestiona la estructura del proyecto bajo $GOPATH. Si hacemos un go get github.com/gohugoio/hugoclonará el repositorio bajo

$ GOPATH / src / repository_remote / user_name / project_name


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

Esta es una buena manera de crear su ruta de proyecto inicial . Ahora exploremos cuáles son los tipos de proyectos y cómo se organizan sus estructuras internas. Todos los proyectos de golang en la comunidad se pueden clasificar en

  • Libraries (sin binarios ejecutables)
  • Single Project (contiene solo 1 binario ejecutable)
  • Tooling Projects (contiene múltiples archivos binarios ejecutables)

En general, los archivos de proyecto golang se pueden empaquetar bajo cualquier principio de diseño , como DDD , POD

La mayoría de los proyectos disponibles siguen este diseño orientado a paquetes

El diseño orientado a paquetes alienta al desarrollador a mantener la implementación solo dentro de sus propios paquetes, aparte del /internalpaquete que esos paquetes no pueden comunicarse entre sí


Bibliotecas

  • Proyectos como controladores de bases de datos , qt se pueden poner en esta categoría.
  • Algunas bibliotecas, como el color , ahora siguen una estructura plana sin ningún otro paquete.
  • La mayoría de estos proyectos de biblioteca maneja un paquete llamado interno .
  • /internal El paquete se utiliza principalmente para ocultar la implementación de otros proyectos.
  • No tiene archivos binarios ejecutables, por lo que no hay archivos que contengan la función principal .

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

Proyecto individual

  • Proyectos como hugo , etcd tienen una sola función principal en el nivel raíz y.
  • El objetivo es generar un solo binario

Proyectos de herramientas

  • Proyectos como kubernetes , go-ethereum tienen múltiples funciones principales organizadas bajo un paquete llamado cmd
  • cmd/ El paquete gestiona la cantidad de binarios (herramientas) que queremos construir

 ~/$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
fuente