Skip to content

Modules

Chaque langage moderne dispose de son propre outil de gestion des dépendances mature, tel que Gradle pour Java, Pip pour Python, Npm pour NodeJs, etc. Un bon outil de gestion des dépendances peut faire gagner beaucoup de temps aux développeurs et améliorer l'efficacité du développement. Cependant, Go ne disposait pas d'une solution de gestion des dépendances mature à ses débuts. À cette époque, tout le code était stocké dans le répertoire GOPATH, ce qui n'était pas très convivial pour les projets d'ingénierie, avec des versions chaotiques et des dépendances difficiles à gérer. Pour résoudre ce problème, les développeurs de la communauté ont proposé diverses solutions, créant une situation confuse. Parmi celles-ci, certaines solutions se sont démarquées, comme Vendor. Jusqu'à ce que Go 1.11 introduise officiellement Go Mod, l'outil de gestion des dépendances officiel, mettant fin à la confusion précédente et s'améliorant continuellement dans les mises à jour suivantes, éliminant les anciens outils. Aujourd'hui, au moment de la rédaction de cet article, la version de Go est la 1.20, et presque tous les projets Go utilisent Go Mod. Ainsi, cet article ne présentera que Go Mod. L'équipe officielle a également rédigé une documentation très détaillée sur les modules Go : Référence des modules Go.

Écriture d'un module

Go Module est essentiellement basé sur VCS (Version Control System). Lorsque vous téléchargez des dépendances, vous exécutez en réalité des commandes VCS, comme git. Donc, si vous souhaitez partager une bibliothèque que vous avez écrite, il vous suffit de respecter les trois points suivants :

  • Le dépôt de code source doit être accessible publiquement, et le VCS doit être l'un des suivants :
    • git
    • hg (Mercurial)
    • bzr (Bazaar)
    • svn
    • fossil
  • Être un projet go mod conforme aux normes
  • Respecter les normes de versionnement sémantique

Ainsi, il vous suffit de développer normalement avec VCS et de taguer vos versions spécifiques avec des tags conformes aux normes. Les autres utilisateurs pourront alors télécharger votre bibliothèque via le nom du module. Nous allons démontrer les étapes de développement d'un module à l'aide d'un exemple.

Dépôt d'exemple : 246859/hello: say hello (github.com)

Préparation

Avant de commencer, assurez-vous que votre version est suffisamment récente pour prendre en charge complètement go mod (go >= 1.17) et que Go Module est activé. Utilisez la commande suivante pour vérifier s'il est activé :

bash
$ go env GO111MODULE

S'il n'est pas activé, utilisez la commande suivante pour activer Go Module :

bash
$ go env -w GO111MODULE=on

Création

Tout d'abord, vous avez besoin d'un dépôt de code source accessible publiquement. Il y a plusieurs choix, mais je recommande Github. Créez un nouveau projet nommé hello. Bien qu'il n'y ait pas de restrictions particulières sur le nom du dépôt, il est recommandé de ne pas utiliser de caractères spéciaux, car cela pourrait affecter le nom du module.

Une fois créé, vous pouvez voir que l'URL du dépôt est https://github.com/246859/hello, et le nom du module Go correspondant est github.com/246859/hello.

Ensuite, clonez-le localement et initialisez le module avec la commande go mod init :

bash
$ 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/hello

Écriture

Vous pouvez maintenant commencer le développement. La fonctionnalité est très simple, avec une seule fonction :

go
// 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)
}

Écrivez également un fichier de test pour les tests unitaires :

go
// 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)
        }

}

Ensuite, écrivez un programme en ligne de commande pour afficher hello. La fonctionnalité est également très simple. Pour les programmes en ligne de commande, selon les normes, ils doivent être créés dans cmd/app_name/ du projet. Ainsi, les fichiers du programme en ligne de commande hello sont stockés dans le répertoire cmd/hello/, puis écrivez le code pertinent.

go
// 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())
  }
}

Test

Après l'écriture, formatez le code source et testez :

bash
$ go fmt && go vet ./...

$ go test -v .
=== RUN   TestHello
--- PASS: TestHello (0.00s)
PASS
ok      github.com/246859/hello 0.023s

Exécutez le programme en ligne de commande :

bash
$ go run ./cmd/hello -name jack
hello jack!

Documentation

Enfin, écrivez un README clair et concis pour cette bibliothèque, afin que les autres développeurs sachent comment l'utiliser en un coup d'œil :

markdown
# 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)
}
```

Ceci est un document README très simple, vous pouvez l'enrichir vous-même.

Téléversement

Lorsque tout le code est écrit et testé, vous pouvez soumettre les modifications et les pousser vers le dépôt distant.

bash
$ 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(-)

Six commits au total, ce n'est pas beaucoup. Après la soumission, créez un tag pour le dernier commit :

bash
$ 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 commit

Enfin, poussez vers le dépôt distant :

bash
$ 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.0

Après avoir poussé, créez une release (un tag suffit, la release est juste pour respecter les normes Github) :

Ainsi, l'écriture du module est terminée. Ce qui précède est le processus de base du développement d'un module. Les autres développeurs peuvent maintenant importer le code ou installer les outils en ligne de commande via le nom du module.

Importation

Importez la bibliothèque avec go get :

bash
$ go get github.com/246859/hello@latest
go: downloading github.com/246859/hello v1.0.0
go: added github.com/246859/hello v1.0.0

Installez le programme en ligne de commande avec go install :

bash
$ go install github.com/246859/hello/cmd/hello@latest && hello -name jack
hello jack!

Ou exécutez directement avec go run :

bash
$ go run -mod=mod github.com/246859/hello/cmd/hello -name jack
hello jack!

Lorsqu'une bibliothèque est importée, Go Package crée automatiquement une page pour elle. Ce processus est automatique et ne nécessite aucun travail de la part du développeur. Par exemple, la bibliothèque hello dispose d'une page de documentation exclusive, comme illustré ci-dessous.

Pour plus de détails sur le téléversement de modules, consultez Ajouter un package.

Pour savoir comment supprimer les informations d'un module, consultez Supprimer un package.

Configuration du proxy

Bien que Go ne dispose pas d'un dépôt central similaire à Maven Repo, PyPi ou NPM, il existe un dépôt proxy officiel : Services de modules Go (golang.org). Il met en cache les modules téléchargés par les développeurs en fonction de la version et du nom du module. Cependant, comme ses serveurs sont déployés à l'étranger, la vitesse d'accès n'est pas très conviviale pour les utilisateurs nationaux. Nous devons donc modifier l'adresse du proxy de module par défaut. Actuellement, les meilleurs en Chine sont les suivants :

Ici, nous choisissons le proxy de Qiniu Cloud. Exécutez la commande suivante pour modifier le proxy Go, où direct signifie que si le téléchargement via le proxy échoue, il contourne le cache du proxy pour accéder directement au dépôt de code source.

sh
$ go env -w GOPROXY=https://goproxy.cn,direct

Une fois le proxy modifié avec succès, le téléchargement des dépendances sera très rapide à l'avenir.

Téléchargement des dépendances

Après avoir modifié le proxy, essayons d'installer une dépendance tierce. Go dispose d'un site web dédié à la recherche de dépendances : Go Packages.

Importation de code

Recherchez le célèbre framework Web Gin dedans.

De nombreux résultats de recherche apparaîtront. Lors de l'utilisation de dépendances tierces, il faut décider d'adopter ou non la dépendance en fonction du nombre de citations et de la date de mise à jour. Ici, nous choisissons directement le premier :

Après être entré dans la page correspondante, vous pouvez voir qu'il s'agit d'une page de documentation de la dépendance, avec beaucoup d'informations détaillées à son sujet. Vous pouvez également y consulter la documentation ultérieurement.

Il suffit de copier son adresse, puis d'utiliser la commande go get dans le projet créé précédemment, comme suit :

sh
$ go get github.com/gin-gonic/gin

De nombreuses dépendances seront téléchargées pendant le processus. Tant qu'il n'y a pas d'erreur, le téléchargement a réussi.

sh
$ 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.1

Après avoir terminé, consultez le fichier go.mod :

sh
$ 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
)

Vous pouvez constater qu'il y a beaucoup plus de choses qu'auparavant, et vous remarquerez également qu'un fichier nommé go.sum est apparu dans le répertoire :

sh
$ ls
go.mod  go.sum  main.go

Nous y reviendrons plus tard. Modifiez le fichier main.go avec le code suivant :

go
package main

import (
  "github.com/gin-gonic/gin"
)

func main() {
  gin.Default().Run()
}

Exécutez à nouveau le projet :

sh
$ 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 :8080

Ainsi, avec une seule ligne de code, nous avons lancé un serveur Web des plus simples. Lorsqu'une dépendance n'est plus nécessaire, vous pouvez également utiliser la commande go get pour la supprimer. Prenons l'exemple de la suppression de Gin :

sh
$ go get github.com/gin-gonic/gin@none
go: removed github.com/gin-gonic/gin v1.9.0

Ajoutez @none après l'adresse de la dépendance pour la supprimer. Le résultat indique que la suppression a réussi. En consultant à nouveau le fichier go.mod, vous constaterez que la dépendance Gin a disparu.

sh
$ cat go.mod | grep github.com/gin-gonic/gin

Pour mettre à niveau vers la dernière version, ajoutez le suffixe @latest, ou vous pouvez rechercher vous-même les numéros de version Release disponibles :

sh
$ go get -u github.com/gin-gonic/gin@latest

Installation en ligne de commande

La commande go install télécharge la dépendance tierce localement et la compile en un fichier binaire. Grâce à la vitesse de compilation de Go, ce processus ne prend généralement pas beaucoup de temps. Ensuite, Go le stocke dans le répertoire $GOPATH/bin ou $GOBIN, afin qu'il puisse être exécuté globalement (à condition que vous ayez ajouté ces chemins aux variables d'environnement).

TIP

Lors de l'utilisation de la commande install, vous devez spécifier un numéro de version.

Par exemple, téléchargez le débogueur delve écrit en Go :

bash
$ 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.

Gestion des modules

Tout ce qui précède ne fait que décrire l'utilisation de base de Go Mod, mais en réalité, apprendre Go Mod ne se limite pas à cela. La définition officielle d'un module est : un ensemble de packages marqués par une version. Dans la définition ci-dessus, le concept de package devrait être familier, et la version doit suivre le versionnement sémantique, défini au format v(majeur).(mineur).(correctif). Par exemple, la version de Go v1.20.1, le numéro de version majeur est 1, le numéro de version mineur est 20, le numéro de correctif est 1, ce qui donne v1.20.1. Voici des explications plus détaillées :

  • majeur : Lorsque la version majeure change, cela signifie que le projet a subi des modifications incompatibles. Les projets anciens mis à niveau vers la nouvelle version ne fonctionneront probablement pas correctement.
  • mineur : Lorsque la version mineure change, cela signifie que le projet a ajouté de nouvelles fonctionnalités, basées sur la version précédente.
  • correctif : Lorsque la version correctif change, cela signifie simplement que des bugs ont été corrigés, sans ajouter de nouvelles fonctionnalités.

Commandes courantes

CommandeDescription
go mod downloadTélécharge les dépendances du projet actuel
go mod editÉdite le fichier go.mod
go mod graphAffiche le graphe des dépendances du module
go mod initInitialise go mod dans le répertoire actuel
go mod tidyNettoie les modules du projet
go mod verifyVérifie la légalité des dépendances du projet
go mod whyExplique où le projet utilise les dépendances
go clean -modcacheSupprime le cache des dépendances du projet
go list -mListe les modules

Consultez commande go mod pour plus d'informations sur les commandes.

Stockage des modules

Lors de l'utilisation de Go Mod pour la gestion de projet, le cache des modules est stocké par défaut dans le répertoire $GOPATH/pkg/mod. Vous pouvez également modifier $GOMODCACHE pour le stocker à un autre emplacement.

sh
$ go env -w GOMODCACHE=votre_chemin_de_cache_module

Tous les projets Go Module sur la même machine partagent le cache de ce répertoire. Le cache n'a pas de limite de taille et n'est pas automatiquement supprimé. Les fichiers source des dépendances décompressés dans le cache sont en lecture seule. Pour vider le cache, exécutez la commande suivante :

sh
$ go clean -modcache

Le répertoire $GOMODCACHE/cache/download contient les fichiers originaux des dépendances, y compris les fichiers de hachage, les archives originales, etc. Par exemple :

bash
$ 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.ziphash

L'organisation des dépendances après décompression est la suivante, c'est-à-dire le code source du module spécifié :

bash
$ ls $(go env GOMODCACHE)/github.com/246859/hello@v1.0.0 -1
LICENSE
README.md
cmd/
example/
go.mod
hello.go
hello_test.go

Sélection de version

Lors de la sélection des versions de dépendances, Go suit le principe de sélection de version minimale. Voici un exemple du site officiel : le module principal importe la version 1.2 du module A et la version 1.2 du module B. La version 1.2 du module A importe la version 1.3 du module C, et la version 1.2 du module B importe la version 1.4 du module C. Les versions 1.3 et 1.4 du module C importent toutes deux la version 1.2 du module D. Selon le principe de version minimale utilisable, Go sélectionnera finalement les versions A1.2, B1.2, C1.4 et D1.2. Parmi celles-ci, le bleu clair indique les fichiers go.mod chargés, et les cases indiquent les versions finalement sélectionnées.

Le site officiel fournit également d'autres exemples, qui sont globalement similaires.

go.mod

Chaque création d'un projet Go Mod génère un fichier go.mod, il est donc nécessaire de se familiariser avec ce fichier, bien que dans la plupart des cas, il ne soit pas nécessaire de le modifier manuellement.

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
)

Dans le fichier, vous pouvez constater que la plupart des adresses de dépendances contiennent des termes comme github. Cela est dû au fait que Go ne dispose pas d'un dépôt de dépendances public. La plupart des projets open source sont hébergés sur GitHub, tandis que certains ont leurs propres dépôts, comme google.golang.org/protobuf et golang.org/x/crypto. En général, cette série d'URL est également le nom du module du projet Go, ce qui pose un problème : les URL ne distinguent pas les majuscules des minuscules, mais les répertoires de stockage des dépendances les distinguent. Ainsi, go get github.com/gin-gonic/gin et go get github.com/gin-gonic/Gin importent la même dépendance, mais le chemin de stockage local est différent. Dans ce cas, Go ne prend pas directement les lettres majuscules comme chemin de stockage, mais les échappe en !lettre minuscule. Par exemple, github.com\BurntSushi sera finalement échappé en github.com\!burnt!sushi.

module

Le mot-clé module déclare le nom du module du projet actuel. Un fichier go.mod ne peut contenir qu'un seul mot-clé module. Dans l'exemple :

module golearn

Cela signifie que le nom du module actuel est golearn. Par exemple, en ouvrant le fichier go.mod de la dépendance Gin, vous pouvez trouver son nom de module :

module github.com/gin-gonic/gin

Le nom du module de Gin est l'adresse utilisée lors du téléchargement de la dépendance. C'est également le format recommandé pour les noms de modules : domaine/utilisateur/dépôt.

TIP

Un point important à noter est que lorsque la version majeure est supérieure à 1, le numéro de version majeur doit être inclus dans le nom du module. Par exemple :

github.com/my/example

Si la version est mise à niveau vers v2.0.0, le nom du module doit être modifié comme suit :

github.com/my/example/v2

Si un projet existant importe l'ancienne version et que la nouvelle version n'est pas différenciée, lors de l'importation de la dépendance, comme les chemins sont identiques, l'utilisateur ne peut pas distinguer les changements incompatibles dus aux modifications de la version majeure, ce qui peut entraîner des erreurs de programme.

Deprecation

Commentez Deprecated au début de la ligne précédente de module pour indiquer que le module est déprécié. Par exemple :

// Deprecated: use example.com/mod/v2 instead.
module example.com/mod

go

Le mot-clé go indique la version de Go utilisée pour écrire le projet actuel. Le numéro de version doit suivre les règles de versionnement sémantique. Selon la version de Go, Go Mod se comportera différemment. Voici un exemple simple. Consultez la documentation officielle pour les versions de Go disponibles.

go 1.20

require

Le mot-clé require indique qu'une dépendance externe est importée. Par exemple :

require github.com/gin-gonic/gin v1.9.0

Le format est require nom_du_module version. S'il y a plusieurs importations, vous pouvez les regrouper entre parenthèses :

require (
   github.com/bytedance/sonic v1.8.0 // indirect
)

Les dépendances avec le commentaire // indirect signifient qu'elles ne sont pas directement importées par le projet actuel. Elles peuvent être importées par les dépendances directement importées par le projet, donc elles sont des importations indirectes pour le projet actuel. Comme mentionné précédemment, les changements de version majeure doivent être reflétés dans le nom du module. Les modules qui ne respectent pas cette règle sont appelés modules non conformes. Lors de l'importation avec require, un commentaire incompatible sera ajouté.

require example.com/m v4.1.2+incompatible

Pseudo-version

Dans le fichier go.mod ci-dessus, vous pouvez constater que certaines versions de dépendances ne sont pas des numéros de version sémantiques, mais une série de chaînes incompréhensibles. Il s'agit en réalité du CommitID de la version correspondante. Les versions sémantiques font généralement référence à une Release. Les pseudo-versions peuvent spécifier un Commit particulier. Le format est généralement vx.y.z-yyyyMMddHHmmss-CommitId. Comme son vx.y.z n'existe pas nécessairement réellement, on l'appelle pseudo-version. Par exemple, dans l'exemple ci-dessous, v0.0.0 n'existe pas, seuls les 12 chiffres du CommitID suivants sont valides.

// CommitID prend généralement les 12 premiers caractères
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect

De même, lors du téléchargement de dépendances, vous pouvez spécifier le CommitID pour remplacer le numéro de version sémantique :

go get github.com/chenzhuoyu/base64x@fe3a3abad311

exclude

Le mot-clé exclude indique de ne pas charger une version spécifique de dépendance. Si require importe également la même version de dépendance, elle sera ignorée. Ce mot-clé n'est effectif que dans le module principal. Par exemple :

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 remplacera une version spécifique de dépendance. Vous pouvez utiliser le chemin et la version du module pour remplacer, ou un chemin de fichier local spécifié. Exemple :

text
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
)

Seule la version à gauche de => est remplacée. Les autres versions de la même dépendance peuvent toujours être accessibles normalement. Que vous utilisiez un chemin local ou un chemin de module pour spécifier le remplacement, si le module de remplacement possède un fichier go.mod, sa directive module doit correspondre au chemin du module remplacé.

retract

La directive retract indique qu'il ne faut pas dépendre des versions ou plages de versions spécifiées par retract. Par exemple, si un problème majeur est découvert après la publication d'une nouvelle version, vous pouvez utiliser la directive retract.

Retirer certaines versions :

text
retract (
    v1.0.0 // Published accidentally.
    v1.0.1 // Contains retractions only.
)

Retirer une plage de versions :

text
retract v1.0.0
retract [v1.0.0, v1.9.9]
retract (
    v1.0.0
    [v1.0.0, v1.9.9]
)

go.sum

Le fichier go.sum n'existe pas lors de la création initiale d'un projet. Il est généré uniquement lorsque des dépendances externes sont réellement importées. Le fichier go.sum n'est pas adapté à la lecture humaine et il n'est pas recommandé de le modifier manuellement. Son rôle principal est de résoudre les problèmes de construction cohérente, c'est-à-dire que différentes personnes dans différents environnements utilisant le même projet doivent importer exactement les mêmes dépendances lors de la construction. Cela ne peut pas être garanti uniquement par un fichier go.mod.

Voyons maintenant ce que fait Go du début à la fin lors du téléchargement d'une dépendance. Tout d'abord, utilisez la commande suivante pour télécharger une dépendance :

go get github.com/bytedance/sonic v1.8.0

La commande go get commence par télécharger le package de dépendance dans le répertoire de cache local, généralement $GOMODCACHE/cache/download/. Ce répertoire divise les dépendances de différents sites Web par nom de domaine, vous pourriez donc voir la structure de répertoire suivante :

sh
$ 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/

Ainsi, le chemin de stockage de la dépendance téléchargée dans l'exemple ci-dessus est :

$GOMODCACHE/cache/download/github.com/bytedance/sonic/@v/

La structure de répertoire possible est la suivante, avec plusieurs fichiers nommés par version :

sh
$ 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.ziphash

En général, il doit y avoir un fichier list dans ce répertoire, utilisé pour enregistrer les numéros de version connus de la dépendance. Pour chaque version, il y aura les fichiers suivants :

  • zip : archive source de la dépendance
  • ziphash : valeur de hachage calculée à partir de l'archive de la dépendance
  • info : métadonnées de version au format JSON
  • mod : fichier go.mod de cette version
  • lock : fichier temporaire, l'officiel n'a pas expliqué à quoi il sert

En général, Go calcule les valeurs de hachage des deux fichiers, l'archive et go.mod, puis interroge la valeur de hachage de la dépendance sur le serveur spécifié par GOSUMDB (par défaut sum.golang.org). Si la valeur de hachage calculée localement ne correspond pas au résultat de la requête, l'exécution ne se poursuivra pas. Si elles correspondent, Go mettra à jour le fichier go.mod et insérera deux entrées dans le fichier go.sum, comme suit :

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 désactivé, Go écrira directement la valeur de hachage calculée localement dans le fichier go.sum. Il n'est généralement pas recommandé de faire cela.

Normalement, chaque dépendance aura deux entrées : la première est la valeur de hachage de l'archive, la seconde est la valeur de hachage du fichier go.mod de la dépendance. Le format d'enregistrement est nom_du_module version nom_algorithme:valeur_de_hachage. Certaines dépendances plus anciennes peuvent ne pas avoir de fichier go.mod, donc il n'y aura pas de deuxième entrée de hachage. Lorsque ce projet est construit dans un autre environnement, Go calculera la valeur de hachage des dépendances locales spécifiées dans go.mod et la comparera avec les valeurs de hachage enregistrées dans go.sum. Si les valeurs de hachage ne correspondent pas, cela signifie que les versions de dépendances sont différentes et la construction sera refusée. Dans ce cas, les dépendances locales et le fichier go.sum peuvent avoir été modifiés, mais comme go.sum est enregistré après une requête GOSUMDB, Go aura tendance à faire davantage confiance au fichier go.sum.

Modules privés

La plupart des outils Go Mod sont destinés aux projets open source, mais Go prend également en charge les modules privés. Pour les projets privés, il est généralement nécessaire de configurer les variables d'environnement suivantes pour gérer les modules privés :

  • GOPROXY : ensemble de serveurs proxy pour les dépendances
  • GOPRIVATE : liste de modèles génériques de préfixes de chemins de modules privés. Si le nom du module correspond aux règles, cela signifie que le module est un module privé. Le comportement est le même que GONOPROXY et GONOSUMDB.
  • GONOPROXY : liste de modèles génériques de préfixes de chemins de modules qui ne sont pas téléchargés via le proxy. Si cela correspond, le téléchargement du module n'utilisera pas GOPROXY et tentera de télécharger directement depuis le système de contrôle de version.
  • GONOSUMDB : liste de modèles génériques de préfixes de chemins de modules qui ne subissent pas de validation publique GOSUMDB. Si cela correspond, la validation du module n'utilisera pas la base de données publique de checksum.
  • GOINSECURE : liste de modèles génériques de préfixes de chemins de modules qui peuvent être récupérés via HTTP et d'autres protocoles non sécurisés.

Espaces de travail

Comme mentionné précédemment, le fichier go.mod prend en charge la directive replace, ce qui nous permet d'utiliser temporairement des modifications locales qui n'ont pas encore été publiées, comme suit :

replace (
  github.com/246859/hello v1.0.1 => ./hello
)

Lors de la compilation, Go utilisera le module hello local, puis le supprimera lors de la publication d'une nouvelle version à l'avenir.

Cependant, l'utilisation de la directive replace modifiera le contenu du fichier go.mod, et cette modification pourrait être accidentellement soumise au dépôt distant. C'est quelque chose que nous ne souhaitons pas, car la cible spécifiée par la directive replace est un chemin de fichier et non une URL réseau. Le chemin qui fonctionne sur cette machine peut ne pas fonctionner sur une autre, et les chemins de fichiers posent également un problème important pour la compatibilité multiplateforme. Pour résoudre ce type de problèmes, les espaces de travail ont été créés.

Les espaces de travail (workspace) sont une nouvelle solution de gestion multi-module introduite par Go en 1.18, visant à mieux effectuer le développement multi-module local. Nous allons l'expliquer à l'aide d'un exemple.

Dépôt d'exemple : 246859/work: go work example (github.com)

Exemple

Tout d'abord, le projet contient deux modules Go indépendants, auth et user :

bash
$ ls -1
LICENSE
README.md
auth
go.work
user

Le module auth dépend de la structure User du module user, comme suit :

go
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")
}

Le contenu du module user est le suivant :

go
package user

type User struct {
  Name     string
  Password string
  Age      int
}

Dans ce projet, nous pouvons écrire le fichier go.work comme suit :

go 1.22

use (
  ./auth
  ./user
)

Le contenu est très facile à comprendre. Utilisez la directive use pour spécifier quels modules participent à la compilation. Ensuite, exécutez le code du module auth :

go
// 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)
}

Exécutez la commande suivante. Le résultat indique que le module a été importé avec succès.

bash
$ go run ./auth/example
true

Dans les versions précédentes, pour ces deux modules indépendants, si le module auth souhaitait utiliser le code du module user, il n'y avait que deux méthodes :

  1. Soumettre les modifications du module user et les pousser vers le dépôt distant, publier une nouvelle version, puis modifier le fichier go.mod pour la version spécifiée.
  2. Modifier le fichier go.mod pour rediriger la dépendance vers un fichier local.

Les deux méthodes nécessitent de modifier le fichier go.mod. L'existence des espaces de travail vise à permettre l'importation d'autres modules sans modifier le fichier go.mod. Cependant, il est important de comprendre que le fichier go.work est utilisé uniquement pendant le développement. Son existence vise à faciliter le développement local, et non à gérer les dépendances. Il vous permet simplement de sauter temporairement le processus de soumission et de publication, vous permettant d'utiliser immédiatement les nouvelles modifications du module user sans attendre. Lorsque le module user est testé, vous devez toujours publier une nouvelle version, et le module auth doit toujours modifier le fichier go.mod pour importer la dernière version (ce processus peut être effectué avec la commande go work sync). Ainsi, dans le développement Go normal, go.work ne doit pas non plus être soumis au VCS (le go.work dans le dépôt d'exemple est uniquement à des fins de démonstration), car son contenu dépend des fichiers locaux et sa fonctionnalité est limitée au développement local.

Commandes

Voici quelques commandes d'espace de travail :

CommandeDescription
editÉdite go.work
initInitialise un nouvel espace de travail
syncSynchronise les dépendances de module de l'espace de travail
useAjoute un nouveau module à go.work
vendorCopie les dépendances au format vendor

Consultez commande go work pour plus d'informations sur les commandes.

Directives

Le contenu du fichier go.work est très simple, avec seulement trois directives :

  • go, spécifie la version de Go
  • use, spécifie les modules à utiliser
  • replace, spécifie les modules à remplacer

À l'exception de la directive use, les deux autres sont essentiellement équivalentes aux directives dans go.mod, sauf que la directive replace dans go.work s'applique à tous les modules. Un go.work complet est le suivant :

tex
go 1.22

use(
  ./auth
  ./user
)

replace github.com/246859/hello v1.0.0 => /home/jack/code/hello

Golang by www.golangdev.cn edit