Módulos
Cada lenguaje moderno tiene su propia herramienta madura de gestión de dependencias, como Gradle de Java, Pip de Python, Npm de NodeJs, etc. Una buena herramienta de gestión de dependencias puede ahorrar mucho tiempo a los desarrolladores y mejorar la eficiencia del desarrollo. Sin embargo, Go no tenía una solución madura de gestión de dependencias en sus primeros días. Todo el código se almacenaba en el directorio GOPATH, lo cual era muy poco amigable para los proyectos de ingeniería: versiones caóticas, dependencias difíciles de gestionar. Para resolver este problema, los desarrolladores de la comunidad debatieron intensamente, creando una situación confusa. Durante este período surgieron algunas soluciones destacadas como Vendor. Finalmente, en Go 1.11, el equipo oficial lanzó Go Mod, la herramienta oficial de gestión de dependencias, poniendo fin al caos anterior. Continuó mejorando en actualizaciones posteriores y eliminó las herramientas antiguas. Hasta la fecha, al escribir este artículo, la versión de Go ha llegado a 1.20, y casi todos los proyectos de Go utilizan Go Mod. Por lo tanto, en este artículo solo se presentará Go Mod. El equipo oficial también ha escrito documentación muy detallada sobre los módulos de Go: Go Modules Reference.
Escribir un Módulo
Go Module se basa esencialmente en VCS (Sistema de Control de Versiones). Cuando descargas dependencias, en realidad estás ejecutando comandos VCS, como git. Por lo tanto, si quieres compartir una biblioteca que has escrito, solo necesitas cumplir con los siguientes tres puntos:
- El repositorio de código fuente debe ser accesible públicamente, y el VCS debe ser uno de los siguientes:
- git
- hg (Mercurial)
- bzr (Bazaar)
- svn
- fossil
- Ser un proyecto go mod que cumpla con las especificaciones
- Cumplir con las especificaciones de versionado semántico
Por lo tanto, solo necesitas desarrollar normalmente usando VCS y etiquetar tus versiones específicas con Tags que cumplan con los estándares. Otros podrán descargar tu biblioteca mediante el nombre del módulo. A continuación, demostraremos los pasos para desarrollar un módulo mediante un ejemplo.
Repositorio de ejemplo: 246859/hello: say hello (github.com)
Preparación
Antes de comenzar, asegúrate de que tu versión sea compatible con go mod (go >= 1.17) y que Go Module esté habilitado. Usa el siguiente comando para verificar si está activado:
$ go env GO111MODULESi no está habilitado, usa el siguiente comando para activar Go Module:
$ go env -w GO111MODULE=onCreación
Primero necesitas un repositorio de código fuente accesible públicamente. Hay muchas opciones, pero recomiendo Github. Crea un nuevo proyecto llamado hello. Aunque no hay restricciones especiales para el nombre del repositorio, se recomienda no usar caracteres especiales, ya que esto afectaría el nombre del módulo.

Después de crearlo, puedes ver que la URL del repositorio es https://github.com/246859/hello, y el nombre del módulo de Go correspondiente es github.com/246859/hello.

Luego clónalo localmente e inicializa el módulo con el comando go mod init:
$ git clone git@github.com:246859/hello.git
Cloning into 'hello'...
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 5 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (5/5), done.
$ cd hello && go mod init github.com/246859/hello
go: creating new go.mod: module github.com/246859/helloEscritura
Luego puedes comenzar el desarrollo. Su funcionalidad es muy simple, solo tiene una función:
// hello.go
package hello
import "fmt"
// Hello returns hello message
func Hello(name string) string {
if name == "" {
name = "world"
}
return fmt.Sprintf("hello %s!", name)
}También escribe un archivo de prueba para pruebas unitarias:
// hello_test.go
package hello_test
import (
"testing"
"fmt"
"github.com/246859/hello"
)
func TestHello(t *testing.T) {
data := "jack"
expected := fmt.Sprintf("hello %s!", data)
result := hello.Hello(data)
if result != expected {
t.Fatalf("expected result %s, but got %s", expected, result)
}
}A continuación, continúa escribiendo un programa de línea de comandos para output hello. Su funcionalidad también es muy simple. Para los programas de línea de comandos, según las especificaciones, deben crearse en cmd/app_name/ del proyecto. Por lo tanto, los archivos del programa de línea de comandos hello se almacenan en el directorio cmd/hello/, y luego escribes el código relacionado allí.
// cmd/hello/main.go
package main
import (
"flag"
"github.com/246859/hello"
"os"
)
var name string
func init() {
flag.StringVar(&name, "name", "world", "name to say hello")
}
func main() {
flag.Parse()
msg := hello.Hello(name)
_, err := os.Stdout.WriteString(msg)
if err != nil {
os.Stderr.WriteString(err.Error())
}
}Pruebas
Después de escribirlo, formatea el código fuente y prueba:
$ go fmt && go vet ./...
$ go test -v .
=== RUN TestHello
--- PASS: TestHello (0.00s)
PASS
ok github.com/246859/hello 0.023sEjecuta el programa de línea de comandos:
$ go run ./cmd/hello -name jack
hello jack!Documentación
Finalmente, necesitas escribir un README conciso y claro para esta biblioteca, para que otros desarrolladores sepan cómo usarla con solo echar un vistazo:
# hello
just say hello
## Install
import code
```bash
go get github.com/246859/hello@latest
```
install cmd
```bash
go install github.com/246859/hello/cmd/hello@latest
```
## Example
Here's a simple example as follows:
```go
package main
import (
"fmt"
"github.com/246859/hello"
)
func main() {
result := hello.Hello("jack")
fmt.Println(result)
}
```Este es un documento README muy simple. También puedes enriquecerlo tú mismo.
Carga
Cuando todo el código esté escrito y probado, puedes enviar los cambios y hacer push al repositorio remoto.
$ git add go.mod hello.go hello_test.go cmd/ example/ README.md
$ git commit -m "chore(mod): mod init" go.mod
[main 5087fa2] chore(mod): mod init
1 file changed, 3 insertions(+)
create mode 100644 go.mod
$ git commit -m "feat(hello): complete Hello func" hello.go
[main 099a8bf] feat(hello): complete Hello func
1 file changed, 11 insertions(+)
create mode 100644 hello.go
$ git commit -m "test(hello): complete hello testcase" hello_test.go
[main 76e8c1e] test(hello): complete hello testcase
1 file changed, 17 insertions(+)
create mode 100644 hello_test.go
$ git commit -m "feat(hello): complete hello cmd" cmd/hello/
[main a62a605] feat(hello): complete hello cmd
1 file changed, 22 insertions(+)
create mode 100644 cmd/hello/main.go
$ git commit -m "docs(example): add hello example" example/
[main 5c51ce4] docs(example): add hello example
1 file changed, 11 insertions(+)
create mode 100644 example/main.go
$ git commit -m "docs(README): update README" README.md
[main e6fbc62] docs(README): update README
1 file changed, 27 insertions(+), 1 deletion(-)Seis commits no son muchos. Después de enviarlos, crea un tag para el último commit:
$ git tag v1.0.0
$ git tag -l
v1.0.0
$ git log --oneline
e6fbc62 (HEAD -> main, tag: v1.0.0, origin/main, origin/HEAD) docs(README): update README
5c51ce4 docs(example): add hello example
a62a605 feat(hello): complete hello cmd
76e8c1e test(hello): complete hello testcase
099a8bf feat(hello): complete Hello func
5087fa2 chore(mod): mod init
1f422d1 Initial commitFinalmente, haz push al repositorio remoto:
$ git push --tags
Enumerating objects: 23, done.
Counting objects: 100% (23/23), done.
Delta compression using up to 16 threads
Compressing objects: 100% (17/17), done.
Writing objects: 100% (21/21), 2.43 KiB | 1.22 MiB/s, done.
Total 21 (delta 5), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (5/5), done.
To github.com:246859/hello.git
1f422d1..e6fbc62 main -> main
* [new tag] v1.0.0 -> v1.0.0Después del push, crea un release (un tag es suficiente, el release es solo para cumplir con las especificaciones de github):

De esta manera, la escritura del módulo está completa. Este es el proceso básico de desarrollo de módulos. Otros desarrolladores pueden importar el código o instalar herramientas de línea de comandos mediante el nombre del módulo.
Referencia
Importa la biblioteca con go get:
$ go get github.com/246859/hello@latest
go: downloading github.com/246859/hello v1.0.0
go: added github.com/246859/hello v1.0.0Instala el programa de línea de comandos con go install:
$ go install github.com/246859/hello/cmd/hello@latest && hello -name jack
hello jack!O usa go run para ejecutar directamente:
$ go run -mod=mod github.com/246859/hello/cmd/hello -name jack
hello jack!Cuando una biblioteca es importada, Go Package creará una página para ella. Este proceso es automático y no requiere que el desarrollador haga ningún trabajo. Por ejemplo, la biblioteca hello tiene una página de documentación exclusiva, como se muestra a continuación.

Para más detalles sobre cómo cargar módulos, visita Add a package.
Para información sobre cómo eliminar información de módulos, visita Removing a package.
Configurar Proxy
Aunque Go no tiene un repositorio central similar a Maven Repo, PyPi o NPM, tiene un repositorio proxy oficial: Go modules services (golang.org). Almacena en caché los módulos descargados por los desarrolladores según la versión y el nombre del módulo. Sin embargo, debido a que sus servidores están desplegados en el extranjero, la velocidad de acceso no es amigable para los usuarios nacionales. Por lo tanto, necesitamos modificar la dirección proxy del módulo predeterminada. Actualmente, las mejores opciones nacionales son:

Aquí elegimos el proxy de Qiniu Cloud. Ejecuta el siguiente comando para modificar el proxy de Go, donde direct significa que si la descarga del proxy falla, se omitirá la caché del proxy y se accederá directamente al repositorio de código fuente.
$ go env -w GOPROXY=https://goproxy.cn,directDespués de modificar el proxy correctamente, la descarga de dependencias será muy rápida en el futuro.
Descargar Dependencias
Después de modificar el proxy, intenta instalar una dependencia de terceros. Go tiene un sitio web oficial de consulta de dependencias: Go Packages.
Referencia de Código
Busca el famoso framework Web Gin allí.

Aparecerán muchos resultados de búsqueda. Al usar dependencias de terceros, debes decidir si adoptarlas basándote en la cantidad de referencias y el tiempo de actualización. Aquí elegimos directamente el primero:

Después de entrar en la página correspondiente, puedes ver que esta es una página de documentación de la dependencia, con mucha información detallada sobre ella. También puedes venir aquí para consultar la documentación en el futuro.

Solo necesitas copiar su dirección y luego usar el comando go get en el proyecto creado anteriormente:
$ go get github.com/gin-gonic/ginDurante el proceso se descargarán muchas dependencias. Siempre que no haya errores, significa que la descarga fue exitosa.
$ go get github.com/gin-gonic/gin
go: added github.com/bytedance/sonic v1.8.0
go: added github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311
go: added github.com/gin-contrib/sse v0.1.0
go: added github.com/gin-gonic/gin v1.9.0
go: added github.com/go-playground/locales v0.14.1
go: added github.com/go-playground/universal-translator v0.18.1
go: added github.com/go-playground/validator/v10 v10.11.2
go: added github.com/goccy/go-json v0.10.0
go: added github.com/json-iterator/go v1.1.12
go: added github.com/klauspost/cpuid/v2 v2.0.9
go: added github.com/leodido/go-urn v1.2.1
go: added github.com/mattn/go-isatty v0.0.17
go: added github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421
go: added github.com/modern-go/reflect2 v1.0.2
go: added github.com/pelletier/go-toml/v2 v2.0.6
go: added github.com/twitchyliquid64/golang-asm v0.15.1
go: added github.com/ugorji/go/codec v1.2.9
go: added golang.org/x/arch v0.0.0-20210923205945-b76863e36670
go: added golang.org/x/crypto v0.5.0
go: added golang.org/x/net v0.7.0
go: added golang.org/x/sys v0.5.0
go: added golang.org/x/text v0.7.0
go: added google.golang.org/protobuf v1.28.1
go: added gopkg.in/yaml.v3 v3.0.1Después de completar, verifica el archivo go.mod:
$ cat go.mod
module golearn
go 1.20
require github.com/gin-gonic/gin v1.9.0
require (
github.com/bytedance/sonic v1.8.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.11.2 // indirect
github.com/goccy/go-json v0.10.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.9 // indirect
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
golang.org/x/crypto v0.5.0 // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/text v0.7.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)Puedes ver que hay muchas más cosas que antes. También notarás que hay un nuevo archivo llamado go.sum en el directorio:
$ ls
go.mod go.sum main.goDejemos esto por ahora. Modifica el archivo main.go con el siguiente código:
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
gin.Default().Run()
}Ejecuta el proyecto nuevamente:
$ go run golearn
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080Así, con una sola línea de código, se ejecutó el servidor web más simple. Cuando ya no necesites una dependencia, también puedes usar el comando go get para eliminarla. Aquí tomamos Gin como ejemplo:
$ go get github.com/gin-gonic/gin@none
go: removed github.com/gin-gonic/gin v1.9.0Agregando @none después de la dirección de la dependencia, puedes eliminarla. El resultado también indica que la eliminación fue exitosa. Al verificar el archivo go.mod nuevamente, verás que ya no hay dependencia de Gin:
$ cat go.mod | grep github.com/gin-gonic/ginCuando necesites actualizar a la última versión, puedes agregar el sufijo @latest, o puedes consultar manualmente los números de versión de Release disponibles:
$ go get -u github.com/gin-gonic/gin@latestInstalar Línea de Comandos
El comando go install descargará la dependencia de terceros localmente y la compilará en un archivo binario. Gracias a la velocidad de compilación de Go, este proceso generalmente no toma mucho tiempo. Luego Go lo almacenará en el directorio $GOPATH/bin o $GOBIN, para que el archivo binario pueda ejecutarse globalmente (siempre que hayas agregado estas rutas a las variables de entorno).
TIP
Al usar el comando install, debes especificar el número de versión.
Por ejemplo, descarga el depurador delve escrito en Go:
$ go install github.com/go-delve/delve/cmd/dlv@latest
go: downloading github.com/go-delve/delve v1.22.1
go: downloading github.com/cosiner/argv v0.1.0
go: downloading github.com/derekparker/trie v0.0.0-20230829180723-39f4de51ef7d
go: downloading github.com/go-delve/liner v1.2.3-0.20231231155935-4726ab1d7f62
go: downloading github.com/google/go-dap v0.11.0
go: downloading github.com/hashicorp/golang-lru v1.0.2
go: downloading golang.org/x/arch v0.6.0
go: downloading github.com/cpuguy83/go-md2man/v2 v2.0.2
go: downloading go.starlark.net v0.0.0-20231101134539-556fd59b42f6
go: downloading github.com/cilium/ebpf v0.11.0
go: downloading github.com/mattn/go-runewidth v0.0.13
go: downloading github.com/russross/blackfriday/v2 v2.1.0
go: downloading github.com/rivo/uniseg v0.2.0
go: downloading golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2
$ dlv -v
Error: unknown shorthand flag: 'v' in -v
Usage:
dlv [command]
Available Commands:
attach Attach to running process and begin debugging.
completion Generate the autocompletion script for the specified shell
connect Connect to a headless debug server with a terminal client.
core Examine a core dump.
dap Starts a headless TCP server communicating via Debug Adaptor Protocol (DAP).
debug Compile and begin debugging main package in current directory, or the package specified.
exec Execute a precompiled binary, and begin a debug session.
help Help about any command
test Compile test binary and begin debugging program.
trace Compile and begin tracing program.
version Prints version.
Additional help topics:
dlv backend Help about the --backend flag.
dlv log Help about logging flags.
dlv redirect Help about file redirection.
Use "dlv [command] --help" for more information about a command.Gestión de Módulos
Todo lo anterior solo trata sobre el uso básico de Go Mod. Pero de hecho, aprender Go Mod solo con esto no es suficiente. La definición oficial de módulo es: un conjunto de paquetes etiquetados con versión. En la definición anterior, el concepto de paquete debería ser muy familiar, y la versión debe seguir el versionado semántico, definido en el formato v(major).(minor).(patch). Por ejemplo, la versión de Go v1.20.1, donde la versión principal es 1, la versión menor es 20 y la versión de parche es 1, juntas forman v1.20.1. A continuación hay una explicación más detallada:
major: Cuando la versión principal cambia, significa que el proyecto ha tenido cambios incompatibles. Es muy probable que los proyectos de versiones antiguas no puedan ejecutarse normalmente después de actualizar a la nueva versión.minor: Cuando la versiónminorcambia, significa que el proyecto ha agregado nuevas características, solo se han añadido nuevas funciones sobre la base de la versión anterior.patch: Cuando la versiónpatchcambia, significa que solo se han corregido bugs, sin agregar nuevas funciones.
Comandos Comunes
| Comando | Descripción |
|---|---|
go mod download | Descarga las dependencias del proyecto actual |
go mod edit | Edita el archivo go.mod |
go mod graph | Muestra el gráfico de dependencias del módulo |
go mod init | Inicializa go mod en el directorio actual |
go mod tidy | Limpia los módulos del proyecto |
go mod verify | Verifica la legalidad de las dependencias |
go mod why | Explica dónde se usan las dependencias |
go clean -modcache | Elimina la caché de dependencias del proyecto |
go list -m | Lista los módulos |
Visita go mod cmd para más información sobre los comandos.
Almacenamiento de Módulos
Cuando usas Go Mod para la gestión de proyectos, la caché de módulos se almacena por defecto en el directorio $GOPATH/pkg/mod. También puedes modificar $GOMODCACHE para especificar otra ubicación.
$ go env -w GOMODCACHE=tu_ruta_de_caché_de_módulosTodos los proyectos Go Module en la misma máquina comparten la caché en este directorio. La caché no tiene límite de tamaño y no se elimina automáticamente. Los archivos fuente de dependencias descomprimidos en la caché son de solo lectura. Para limpiar la caché, ejecuta el siguiente comando:
$ go clean -modcacheEn el directorio $GOMODCACHE/cache/download se almacenan los archivos originales de las dependencias, incluyendo archivos hash, paquetes comprimidos originales, etc. Por ejemplo:
$ ls $(go env GOMODCACHE)/cache/download/github.com/246859/hello/@v -1
list
v1.0.0.info
v1.0.0.lock
v1.0.0.mod
v1.0.0.zip
v1.0.0.ziphashLa organización de las dependencias después de descomprimir es la siguiente, que es el código fuente del módulo especificado:
$ ls $(go env GOMODCACHE)/github.com/246859/hello@v1.0.0 -1
LICENSE
README.md
cmd/
example/
go.mod
hello.go
hello_test.goSelección de Versión
Go sigue el principio de selección de versión mínima al seleccionar versiones de dependencias. A continuación hay un ejemplo del sitio web oficial: el módulo principal referencia la versión 1.2 del módulo A y la versión 1.2 del módulo B. Al mismo tiempo, la versión 1.2 del módulo A referencia la versión 1.3 del módulo C, y la versión 1.2 del módulo B referencia la versión 1.4 del módulo C. Además, las versiones 1.3 y 1.4 del módulo C referencian simultáneamente la versión 1.2 del módulo D. Según el principio de versión mínima utilizable, Go finalmente seleccionará las versiones A1.2, B1.2, C1.4 y D1.2. Donde el azul claro indica lo cargado por el archivo go.mod, y lo enmarcado indica la versión finalmente seleccionada.
El sitio web oficial también proporciona otros ejemplos, que son básicamente similares.
go.mod
Cada vez que creas un proyecto Go Mod, se genera un archivo go.mod. Por lo tanto, es necesario familiarizarse con el archivo go.mod, aunque en la mayoría de los casos no es necesario modificarlo manualmente.
module golearn
go 1.20
require github.com/gin-gonic/gin v1.9.0
require (
github.com/bytedance/sonic v1.8.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.11.2 // indirect
github.com/goccy/go-json v0.10.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.9 // indirect
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
golang.org/x/crypto v0.5.0 // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/text v0.7.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)En el archivo, puedes notar que la mayoría de las direcciones de dependencias contienen palabras como github. Esto se debe a que Go no tiene un repositorio de dependencias público. La mayoría de los proyectos de código abierto están alojados en Github, aunque algunos tienen sus propios repositorios, como google.golang.org/protobuf y golang.org/x/crypto. Normalmente, esta cadena de URL es también el nombre del módulo del proyecto Go. Esto plantea un problema: las URL no distinguen entre mayúsculas y minúsculas, pero las carpetas de almacenamiento de dependencias sí. Por lo tanto, go get github.com/gin-gonic/gin y go get github.com/gin-gonic/Gin referencian la misma dependencia, pero la ruta de almacenamiento local es diferente. Cuando esto ocurre, Go no usa directamente las letras mayúsculas como ruta de almacenamiento, sino que las escapa como !letras minúsculas. Por ejemplo, github.com\BurntSushi finalmente se escapa como github.com\!burnt!sushi.
module
La palabra clave module declara el nombre del módulo del proyecto actual. Solo puede aparecer una palabra clave module en un archivo go.mod. En el ejemplo:
module golearnSignifica que el nombre del módulo actual es golearn. Por ejemplo, al abrir el archivo go.mod de la dependencia Gin, puedes ver su nombre module:
module github.com/gin-gonic/ginEl nombre del módulo de Gin es la dirección utilizada al descargar dependencias. Este es también el formato recomendado para los nombres de módulos: dominio/usuario/nombre del repositorio.
TIP
Un punto a tener en cuenta es que cuando la versión principal es mayor que 1, el número de versión principal debe reflejarse en el nombre del módulo. Por ejemplo:
github.com/my/exampleSi la versión se actualiza a v2.0.0, el nombre del módulo debe modificarse a:
github.com/my/example/v2Si los proyectos existentes referencian la versión anterior y la nueva versión no se distingue, al importar dependencias, como las rutas son consistentes, los usuarios no podrán distinguir los cambios incompatibles causados por el cambio de versión principal, lo que podría causar errores en el programa.
Deprecation
Comenta Deprecated al principio de la línea anterior a module para indicar que el módulo está obsoleto. Por ejemplo:
// Deprecated: use example.com/mod/v2 instead.
module example.com/modgo
La palabra clave go indica la versión de Go utilizada para escribir el proyecto actual. El número de versión debe seguir las reglas de versionado semántico. Según la versión de Go, Go Mod mostrará diferentes comportamientos. A continuación hay un ejemplo simple. Consulta la documentación oficial para conocer las versiones de Go disponibles.
go 1.20require
La palabra clave require indica que se ha importado una dependencia externa. Por ejemplo:
require github.com/gin-gonic/gin v1.9.0El formato es require nombre del módulo versión. Cuando hay múltiples referencias, puedes usar paréntesis:
require (
github.com/bytedance/sonic v1.8.0 // indirect
)Los comentarios con // indirect indican que la dependencia no es referenciada directamente por el proyecto actual. Puede ser que una dependencia referenciada directamente por el proyecto haya referenciado esta dependencia, por lo que es una referencia indirecta para el proyecto actual. Como se mencionó anteriormente, los cambios de versión principal deben reflejarse en el nombre del módulo. Los módulos que no siguen esta regla se denominan módulos no conformes. Al hacer require, se agregará el comentario incompatible:
require example.com/m v4.1.2+incompatibleVersiones Pseudo
En el archivo go.mod anterior, puedes notar que algunas versiones de dependencias no son números de versión semánticos, sino cadenas de caracteres incomprensibles. En realidad, estos son los CommitID de las versiones correspondientes. Las versiones semánticas generalmente se refieren a un Release. Los números de versión pseudo pueden especificar un Commit específico. El formato usual es vx.y.z-yyyyMMddHHmmss-CommitId. Dado que su vx.y.z no necesariamente existe realmente, se llama versión pseudo. Por ejemplo, en el siguiente ejemplo, v0.0.0 no existe; lo que realmente es válido son los 12 dígitos del CommitID siguientes:
// CommitID一般取前 12 位
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirectDe manera similar, al descargar dependencias, también puedes especificar el CommitID para reemplazar el número de versión semántico:
go get github.com/chenzhuoyu/base64x@fe3a3abad311exclude
La palabra clave exclude indica que no se debe cargar una versión específica de la dependencia. Si también hay un require que referencia la misma versión, se ignorará. Esta palabra clave solo es efectiva en el módulo principal. Por ejemplo:
exclude golang.org/x/net v1.2.3
exclude (
golang.org/x/crypto v1.4.5
golang.org/x/text v1.6.7
)replace
replace reemplazará una versión específica de la dependencia. Puedes usar la ruta y versión del módulo para reemplazar, o una ruta de archivo local especificada. Ejemplo:
replace golang.org/x/net v1.2.3 => example.com/fork/net v1.4.5
replace (
golang.org/x/net v1.2.3 => example.com/fork/net v1.4.5
golang.org/x/net => example.com/fork/net v1.4.5
golang.org/x/net v1.2.3 => ./fork/net
golang.org/x/net => ./fork/net
)Solo se reemplaza la versión a la izquierda de =>. Otras versiones de la misma dependencia aún se pueden acceder normalmente. Ya sea que uses una ruta local o una ruta de módulo para especificar el reemplazo, si el módulo de reemplazo tiene un archivo go.mod, su directiva module debe coincidir con la ruta del módulo reemplazado.
retract
La directiva retract indica que no se debe depender de la versión o rango de versiones especificado por retract. Por ejemplo, si se descubre un problema grave después de lanzar una nueva versión, puedes usar la directiva retract.
Retirar algunas versiones:
retract (
v1.0.0 // Published accidentally.
v1.0.1 // Contains retractions only.
)Retirar un rango de versiones:
retract v1.0.0
retract [v1.0.0, v1.9.9]
retract (
v1.0.0
[v1.0.0, v1.9.9]
)go.sum
El archivo go.sum no existe al crear un proyecto inicialmente. Solo se genera después de importar dependencias externas. El archivo go.sum no es adecuado para lectura humana y no se recomienda modificarlo manualmente. Su propósito principal es resolver problemas de construcción consistente, es decir, que diferentes personas en diferentes entornos que usan el mismo proyecto deben referenciar exactamente las mismas dependencias al construir. Esto no se puede garantizar solo con un archivo go.mod.
A continuación, veamos qué hace Go de principio a fin al descargar una dependencia. Primero, usa el siguiente comando para descargar una dependencia:
go get github.com/bytedance/sonic v1.8.0El comando go get primero descarga el paquete de dependencias en el directorio de caché local, generalmente $GOMODCACHE/cache/download/. Este directorio divide las dependencias de diferentes sitios web según el nombre de dominio, por lo que podrías ver la siguiente estructura de directorios:
$ ls
cloud.google.com/ go.opencensus.io/ gopkg.in/ nhooyr.io/
dmitri.shuralyov.com/ go.opentelemetry.io/ gorm.io/ rsc.io/
github.com/ go.uber.org/ honnef.co/ sumdb/
go.etcd.io/ golang.org/ lukechampine.com/
go.mongodb.org/ google.golang.org/ modernc.org/Entonces, la ruta donde se almacena la dependencia descargada en el ejemplo anterior es:
$GOMODCACHE/cache/download/github.com/bytedance/sonic/@v/La posible estructura de directorios es la siguiente, con varios archivos nombrados por versión:
$ ls
list v1.8.0.lock v1.8.0.ziphash v1.8.3.mod
v1.5.0.mod v1.8.0.mod v1.8.3.info v1.8.3.zip
v1.8.0.info v1.8.0.zip v1.8.3.lock v1.8.3.ziphashNormalmente, debe haber un archivo list en este directorio para registrar los números de versión conocidos de la dependencia. Para cada versión, habrá los siguientes archivos:
zip: paquete comprimido del código fuente de la dependenciaziphash: valor hash calculado según el paquete comprimido de la dependenciainfo: metadatos de versión en formato JSONmod: archivogo.modde esta versiónlock: archivo temporal, la documentación oficial no explica para qué sirve
Generalmente, Go calculará los valores hash de dos archivos: el paquete comprimido y go.mod. Luego consultará el valor hash de la dependencia según el servidor especificado por GOSUMDB (por defecto es sum.golang.org). Si el valor hash calculado localmente no coincide con el resultado de la consulta, no continuará. Si coincide, actualizará el archivo go.mod e insertará dos registros en el archivo go.sum, aproximadamente así:
github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA=
github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=TIP
Si GOSUMDB está deshabilitado, Go escribirá directamente el valor hash calculado localmente en el archivo go.sum. Generalmente no se recomienda hacer esto.
Normalmente, cada dependencia tendrá dos registros: el primero es el hash del paquete comprimido y el segundo es el hash del archivo go.mod de la dependencia. El formato de registro es nombre del módulo versión nombre del algoritmo:hash. Algunas dependencias más antiguas pueden no tener un archivo go.mod, por lo que no tendrán un segundo registro hash. Cuando este proyecto se construye en el entorno de otra persona, Go calculará el hash de la dependencia local especificada en go.mod y lo comparará con el hash registrado en go.sum. Si los hashes no coinciden, significa que las versiones de las dependencias son diferentes y rechazará la construcción. Cuando esto ocurre, tanto la dependencia local como el archivo go.sum pueden haber sido modificados. Pero dado que go.sum se registra después de la consulta de GOSUMDB, se tiende a confiar más en el archivo go.sum.
Módulos Privados
La mayoría de las herramientas de Go Mod están diseñadas para proyectos de código abierto, pero Go también admite módulos privados. Para proyectos privados, generalmente es necesario configurar las siguientes variables de entorno para manejar la privacidad de los módulos:
GOPROXY: conjunto de servidores proxy de dependenciasGOPRIVATE: lista de patrones comunes de prefijos de ruta de módulos privados. Si el nombre del módulo coincide con las reglas, indica que el módulo es privado. El comportamiento específico es el mismo que GONOPROXY y GONOSUMDB.GONOPROXY: lista de patrones comunes de prefijos de ruta de módulos que no se descargan desde el proxy. Si coincide, al descargar módulos no se usará GOPROXY, intentando descargar directamente desde el sistema de control de versiones.GONOSUMDB: lista de patrones comunes de prefijos de ruta de módulos que no realizan validación pública de GOSUMDB. Si coincide, al verificar módulos no se usará la base de datos pública de checksum.GOINSECURE: lista de patrones comunes de prefijos de ruta de módulos que se pueden recuperar mediante HTTP y otros protocolos inseguros.
Espacios de Trabajo
Anteriormente se mencionó que el archivo go.mod admite la directiva replace, lo que nos permite usar temporalmente modificaciones locales que no han sido lanzadas. Por ejemplo:
replace (
github.com/246859/hello v1.0.1 => ./hello
)Al compilar, Go usará el módulo hello local. Después de lanzar una nueva versión en el futuro, se puede eliminar.
Pero usar la directiva replace modificará el contenido del archivo go.mod, y esta modificación podría enviarse accidentalmente al repositorio remoto. Esto es algo que no queremos, porque el target especificado por la directiva replace es una ruta de archivo local, no una URL de red. Una ruta que funciona en una máquina puede no funcionar en otra. Las rutas de archivo también son un gran problema para la compatibilidad entre plataformas. Para resolver este tipo de problemas, surgieron los espacios de trabajo.
Los espacios de trabajo (workspace) son una nueva solución para la gestión de múltiples módulos introducida en Go 1.18, diseñada para facilitar el desarrollo local de múltiples módulos. A continuación, explicaremos mediante un ejemplo.
Repositorio de ejemplo: 246859/work: go work example (github.com)
Ejemplo
Primero, el proyecto tiene dos módulos de Go independientes: auth y user:
$ ls -1
LICENSE
README.md
auth
go.work
userEl módulo auth depende de la estructura User del módulo user. El contenido es el siguiente:
package auth
import (
"errors"
"github.com/246859/work/user"
)
// Verify user credentials if is ok
func Verify(user user.User) (bool, error) {
password, err := query(user.Name)
if err != nil {
return false, err
}
if password != user.Password {
return false, errors.New("authentication failed")
}
return true, nil
}
func query(username string) (string, error) {
if username == "jack" {
return "jack123456", nil
}
return "", errors.New("user not found")
}El contenido del módulo user es el siguiente:
package user
type User struct {
Name string
Password string
Age int
}En este proyecto, podemos escribir el archivo go.work de la siguiente manera:
go 1.22
use (
./auth
./user
)Su contenido es muy fácil de entender: usa la directiva use para especificar qué módulos participan en la compilación. Luego ejecuta el código en el módulo auth:
// auth/example/main.go
package main
import (
"fmt"
"github.com/246859/work/auth"
"github.com/246859/work/user"
)
func main() {
ok, err := auth.Verify(user.User{Name: "jack", Password: "jack123456"})
if err != nil {
panic(err)
}
fmt.Printf("%v", ok)
}Ejecuta el siguiente comando. Por el resultado, sabemos que el módulo se importó correctamente:
$ go run ./auth/example
trueEn versiones anteriores, para estos dos módulos independientes, si el módulo auth quería usar el código del módulo user, solo había dos opciones:
- Enviar los cambios del módulo user al repositorio remoto, lanzar una nueva versión y luego modificar el archivo
go.moda la versión especificada - Modificar el archivo
go.modpara redirigir la dependencia a un archivo local
Ambos métodos requieren modificar el archivo go.mod. La existencia de los espacios de trabajo es para poder importar otros módulos sin modificar el archivo go.mod. Sin embargo, es importante entender que el archivo go.work solo se usa durante el desarrollo. Su existencia es solo para facilitar el desarrollo local, no para la gestión de dependencias. Solo te permite omitir temporalmente el proceso de envío y lanzamiento, permitiéndote usar inmediatamente las nuevas modificaciones del módulo user sin esperar. Cuando el módulo user se haya probado, finalmente仍需需要发布新版本,并且 auth 模块最后仍然要修改go.mod文件引用最新版本(这一过程可以用go work sync命令来完成)。因此,在正常的 Go 开发过程中,go.work也不应该提交到 VCS 中(示例仓库中的go.work仅用于演示),因为其内容都是依赖于本地的文件,且其功能也仅限于本地开发。
Comandos
A continuación se muestran algunos comandos de espacios de trabajo:
| Comando | Descripción |
|---|---|
| edit | Edita go.work |
| init | Inicializa un nuevo espacio de trabajo |
| sync | Sincroniza las dependencias de módulos del workspace |
| use | Agrega un nuevo módulo a go.work |
| vendor | Copia las dependencias en formato vendor |
Visita go work cmd para más información sobre los comandos.
Directivas
El contenido del archivo go.work es muy simple, solo tiene tres directivas:
go, especifica la versión de Gouse, especifica los módulos a usarreplace, especifica los módulos a reemplazar
Excepto la directiva use, las otras dos son básicamente equivalentes a las directivas en go.mod. Solo que la directiva replace en go.work afecta a todos los módulos. Un go.work completo se ve así:
go 1.22
use(
./auth
./user
)
replace github.com/246859/hello v1.0.0 => /home/jack/code/hello