Skip to content

Riga di Comando

I comandi in Go includono un'intera suite di toolchain che copre documentazione, formattazione, ispezione del codice, compilazione, test, gestione delle dipendenze e molti altri aspetti dello sviluppo Go.

text
bug         Segnala un bug
build       Compila pacchetti e dipendenze
clean       Rimuovi file oggetto
doc         Mostra documentazione nel codice sorgente
env         Visualizza informazioni sulle variabili d'ambiente Go
fix         Risolvi problemi di compatibilità API dovuti a cambiamenti di versione go
fmt         Formatta il codice sorgente
generate    Genera codice
get         Aggiungi dipendenze
install     Installa e compila pacchetti
list        Elenca pacchetti/moduli
mod         Comandi per la manutenzione dei moduli
work        Comandi per la manutenzione dell'area di lavoro
run         Compila ed esegui
test        Esegui test
tool        Esegui uno strumento go specifico
version     Mostra informazioni sulla versione di go
vet         Scansiona e segnala possibili problemi nel codice sorgente

Questo articolo descrive semplicemente il loro utilizzo. Tutti i contenuti fanno riferimento alla documentazione ufficiale. Per ulteriori dettagli, visita cmd/go.

help

Il primo comando da conoscere è help, che permette di leggere l'utilizzo dei comandi. Ci sono due modi d'uso: per ottenere informazioni brevi sull'utilizzo, aggiungi il flag -h dopo il comando specificato, ad esempio

sh
$ go env -h
usage: go env [-json] [-u] [-w] [var ...]
Run 'go help env' for details.

go mostrerà brevemente l'utilizzo del comando e suggerisce di usare il comando help per informazioni più dettagliate

sh
$ go help env
usage: go env [-json] [-u] [-w] [var ...]

Env prints Go environment information.

By default env prints information as a shell script
(on Windows, a batch file). If one or more variable
names is given as arguments, env prints the value of
each named variable on its own line.

The -json flag prints the environment in JSON format
instead of as a shell script.

The -u flag requires one or more arguments and unsets
the default setting for the named environment variables,
if one has been set with 'go env -w'.

The -w flag requires one or more arguments of the
form NAME=VALUE and changes the default settings
of the named environment variables to the given values.

For more about environment variables, see 'go help environment'.

Utilizza saggiamente il comando help per ottenere molte informazioni sui comandi.

doc

sh
$ go doc -h
Usage of [go] doc:
        go doc
        go doc <pkg>
        go doc <sym>[.<methodOrField>]
        go doc [<pkg>.]<sym>[.<methodOrField>]
        go doc [<pkg>.][<sym>.]<methodOrField>
        go doc <pkg> <sym>[.<methodOrField>]
For more information run
        go help doc

Flags:
  -C dir
        change to dir before running command
  -all
        show all documentation for package
  -c    symbol matching honors case (paths not affected)
  -cmd
        show symbols with package docs even if package is a command
  -short
        one-line representation for each symbol
  -src
        show source code for symbol
  -u    show unexported symbols as well as exported

Il comando doc produce documentazione per pacchetti specificati, costanti, funzioni, tipi, variabili, metodi e persino campi di struct. Senza argomenti, produce i commenti del pacchetto corrente

sh
$ go doc

Puoi anche specificare un pacchetto da visualizzare, ad esempio la documentazione del pacchetto runtime

sh
$ go doc runtime
package runtime // import "runtime"

Package runtime contains operations that interact with Go's runtime system,
such as functions to control goroutines. It also includes the low-level type
information used by the reflect package; see reflect's documentation for the
programmable interface to the run-time type system.
......

O un tipo specifico

sh
$ go doc unsafe.Pointer
package unsafe // import "unsafe"

type Pointer *ArbitraryType
    Pointer represents a pointer to an arbitrary type. There are four special
    operations available for type Pointer that are not available for other
    types:
      - A pointer value of any type can be converted to a Pointer.
      - A Pointer can be converted to a pointer value of any type.
      - A uintptr can be converted to a Pointer.
      - A Pointer can be converted to a uintptr.
      ...

O una funzione specifica

sh
$ go doc runtime.GC
package runtime // import "runtime"

func GC()
    GC runs a garbage collection and blocks the caller until the garbage
    collection is complete. It may also block the entire program.

Ha i seguenti flag comuni

  • -u: visualizza tipi privati
  • -all: visualizza tutta la documentazione di un pacchetto specificato
  • -short: solo una breve descrizione su una riga
  • -src: produce il codice sorgente
  • -cmd: produce anche la documentazione del codice per pacchetti che appartengono ai comandi go.

Ad esempio, per visualizzare la variabile runtime.inf, che non è esposta pubblicamente

sh
$ go doc -u runtime.inf
package runtime // import "runtime"

var inf = float64frombits(0x7FF0000000000000)

Utilizzare bene il comando doc per leggere la documentazione in modo più conveniente.

Un altro modo per leggere la documentazione dei comandi è esaminare il codice sorgente, poiché alcuni comandi non hanno documentazione così dettagliata, mentre nel codice sorgente ci sono spiegazioni più approfondite. Poiché questi comandi sono scritti interamente in go, sono facili da leggere. Questi comandi si trovano nel pacchetto src/cmd, ogni sottopacchetto è un comando separato, il punto di ingresso si trova nel file cmd/go/main.go

go
func init() {
    base.Go.Commands = []*base.Command{
       bug.CmdBug,
       work.CmdBuild,
       clean.CmdClean,
       doc.CmdDoc,
       envcmd.CmdEnv,
       fix.CmdFix,
       fmtcmd.CmdFmt,
       generate.CmdGenerate,
       modget.CmdGet,
       work.CmdInstall,
       list.CmdList,
       modcmd.CmdMod,
       workcmd.CmdWork,
       run.CmdRun,
       test.CmdTest,
       tool.CmdTool,
       version.CmdVersion,
       vet.CmdVet,

       help.HelpBuildConstraint,
       help.HelpBuildmode,
       help.HelpC,
       help.HelpCache,
       help.HelpEnvironment,
       help.HelpFileType,
       modload.HelpGoMod,
       help.HelpGopath,
       get.HelpGopathGet,
       modfetch.HelpGoproxy,
       help.HelpImportPath,
       modload.HelpModules,
       modget.HelpModuleGet,
       modfetch.HelpModuleAuth,
       help.HelpPackages,
       modfetch.HelpPrivate,
       test.HelpTestflag,
       test.HelpTestfunc,
       modget.HelpVCS,
    }
}

Qui troverai tutti i sottocomandi di go e le relative informazioni di aiuto.

bug

sh
$ go help bug
usage: go bug

Bug opens the default browser and starts a new bug report.
The report includes useful system information.

Questo comando non ha parametri o flag. Apre il browser predefinito per accedere alla pagina issue del repository github.com/golang/go, facilitando la segnalazione di bug. Non ha altre funzioni.

version

Il comando version mostra le informazioni sulla versione corrente di go.

go
$ go version -h
usage: go version [-m] [-v] [file ...]

Senza parametri, mostra la versione corrente del linguaggio go

sh
$ go version
go version go1.21.0 windows/amd64

Accetta anche percorsi di file come parametri e mostrerà la versione di go utilizzata per compilare tutti i file binari eseguibili riconoscibili in quel percorso.

sh
$ go version -v ./
buf.exe: go1.20.2
cobra-cli.exe: go1.21.0
dlv.exe: go1.20.2
goctl.exe: go1.20.2
goimports.exe: go1.20.2
golangci-lint.exe: go1.20.2
gopls.exe: go1.19.3
kratos.exe: go1.20.2
main.exe: go1.19.1
protoc-gen-go-grpc.exe: go1.20.2
protoc-gen-go-http.exe: go1.20.2
protoc-gen-go.exe: go1.20.2
protoc-gen-openapi.exe: go1.20.2
swag.exe: go1.21.0
wire.exe: go1.21.0

Il parametro -v specifica al comando version di provare a produrre la versione go di file non riconoscibili, il parametro -m produce le informazioni sul modulo del file binario e alcuni parametri di compilazione. Ecco un esempio semplice.

sh
$ go version -v -m wire.exe
wire.exe: go1.21.0
        path    github.com/google/wire/cmd/wire
        mod     github.com/google/wire  v0.5.0  h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8=
        dep     github.com/google/subcommands   v1.0.1  h1:/eqq+otEXm5vhfBrbREPCSVQbvofip6kIz+mX5TUH7k=
        dep     github.com/pmezard/go-difflib   v1.0.0  h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
        dep     golang.org/x/tools      v0.0.0-20190422233926-fe54fb35175b      h1:NVD8gBK33xpdqCaZVVtd6OFJp+3dxkXuz7+U7KaVN6s=
        build   -buildmode=exe
        build   -compiler=gc
        build   DefaultGODEBUG=panicnil=1
        build   CGO_ENABLED=1
        build   CGO_CFLAGS=
        build   CGO_CPPFLAGS=
        build   CGO_CXXFLAGS=
        build   CGO_LDFLAGS=
        build   GOARCH=amd64
        build   GOOS=windows
        build   GOAMD64=v1

go stesso è un file binario. In realtà, senza parametri, go version produce la versione del linguaggio go del proprio file binario, poiché tutta la toolchain di cmd/go è implementata dal linguaggio go stesso.

env

Il comando env permette di visualizzare tutte le variabili d'ambiente go. La modifica di queste variabili d'ambiente influenzerà il comportamento della toolchain go.

sh
$ go env -h
usage: go env [-json] [-u] [-w] [var ...]
Run 'go help env' for details.

Eseguendo questo comando senza parametri, vengono prodotti i valori di tutte le variabili d'ambiente go

sh
$ go env
set GO111MODULE=on
set GOARCH=amd64
...

Passando il nome di una variabile d'ambiente come parametro, si può produrre solo il valore di quella variabile

sh
$ go env GO111MODULE
on

Aggiungendo -json si produce il formato JSON

sh
$ go env -json
{
        "AR": "ar",
        "CC": "gcc",
    ......
}

Usando il flag -w e passando un parametro nella forma var=value, si modifica permanentemente il valore di una variabile

sh
$ go env -w GO111MODULE=on

Usando il flag -u, si può ripristinare una variabile al valore predefinito

sh
$ go env -u GO111MODULE

Eseguendo go help environment si può visualizzare la descrizione di ogni variabile d'ambiente

sh
$ go help environment
The go command and the tools it invokes consult environment variables
for configuration. If an environment variable is unset or empty, the go
command uses a sensible default setting. To see the effective setting of
the variable <NAME>, run 'go env <NAME>'. To change the default setting,
run 'go env -w <NAME>=<VALUE>'. Defaults changed using 'go env -w'
are recorded in a Go environment configuration file stored in the
per-user configuration directory, as reported by os.UserConfigDir.
The location of the configuration file can be changed by setting
the environment variable GOENV, and 'go env GOENV' prints the
effective location, but 'go env -w' cannot change the default location.
See 'go help env' for details.

General-purpose environment variables:

        GO111MODULE
                Controls whether the go command runs in module-aware mode or GOPATH mode.
                May be "off", "on", or "auto".
                See https://golang.org/ref/mod#mod-commands.
        GCCGO
                The gccgo command to run for 'go build -compiler=gccgo'.
        GOARCH
                The architecture, or processor, for which to compile code.
                Examples are amd64, 386, arm, ppc64.
        GOBIN
                The directory where 'go install' will install a command.
        GOCACHE
                The directory where the go command will store cached
                information for reuse in future builds.
    ......

Di seguito sono presentate alcune variabili d'ambiente comunemente utilizzate

GOVERSION

Il valore di questa variabile d'ambiente dipende dalla versione del linguaggio go, e il numero di versione proviene dal file $GOROOT/VERSION, che registra la versione corrente di go e il tempo di compilazione.

sh
$ cat $GOROOT/VERSION
go1.21.3
time 2023-10-09T17:04:35Z

Il valore della variabile runtime.Version è lo stesso di GOVERSION e questa variabile d'ambiente non può essere modificata.

GOENV

Nella directory $GOROOT c'è un file di configurazione predefinito chiamato go.env

sh
$ cat $GOROOT/go.env
# This file contains the initial defaults for go command configuration.
# Values set by 'go env -w' and written to the user's go/env file override these.
# The environment overrides everything else.

# Use the Go module mirror and checksum database by default.
# See https://proxy.golang.org for details.
GOPROXY=https://proxy.golang.org,direct
GOSUMDB=sum.golang.org

# Automatically download newer toolchains as directed by go.mod files.
# See https://go.dev/doc/toolchain for details.
GOTOOLCHAIN=auto

Il formato è semplicemente key=value. I valori delle variabili d'ambiente modificati con il comando go env -w key=value vengono scritti nel file di configurazione. Tuttavia, è possibile non utilizzare il file di configurazione predefinito. La variabile d'ambiente GOENV può specificare manualmente l'indirizzo del file di configurazione env, e il valore della variabile d'ambiente GOENV può essere sovrascritto solo dalle variabili d'ambiente del sistema operativo e non può essere modificato dal comando go env -w.

GOHOSTARCH

Rappresenta l'architettura CPU della macchina locale. Serve solo per visualizzazione. Il valore di questa variabile d'ambiente non viene letto dal file di configurazione e non può essere modificato.

GOHOSTOS

Rappresenta il sistema operativo della macchina locale. Serve solo per visualizzazione. Il valore di questa variabile d'ambiente non viene letto dal file di configurazione e non può essere modificato.

GOOS

Durante la compilazione, il valore di GOOS determina in quale file binario del sistema di destinazione verrà compilato il codice sorgente. Il valore predefinito è GOHOSTOS, ovvero il sistema operativo locale. Ha le seguenti opzioni

  • linux
  • darwin
  • windows
  • netbsd
  • aix
  • android

I sistemi operativi effettivamente supportati non si limitano a questi. Usa il comando go tool dist list per visualizzare tutti i valori supportati

sh
$ go tool dist list | awk -F '/' '{print $1}' | awk '!seen[$0]++'
aix
android
darwin
dragonfly
freebsd
illumos
ios
js
linux
netbsd
openbsd
plan9
solaris
wasip1
windows

GOARCH

Durante la compilazione, il valore di GOARCH determina quale architettura CPU verrà utilizzata durante la compilazione. Il valore predefinito è GOHOSTARCH, ovvero l'architettura CPU locale. Ha le seguenti opzioni

  • amd64
  • 386
  • arm
  • ppc64

Le architetture effettivamente supportate non si limitano a queste. Usa il comando go tool dist list per visualizzare tutti i valori supportati

sh
$ go tool dist list | awk -F '/' '{print $2}' | awk '!seen[$0]++'
ppc64
386
amd64
arm
arm64
riscv64
wasm
loong64
mips
mips64
mips64le
mipsle
ppc64le
s390x

Va notato che GOOS e GOARCH non possono essere combinati arbitrariamente. Alcuni sistemi operativi supportano solo architetture CPU specifiche.

GOROOT

GOROOT rappresenta la directory radice dell'installazione del linguaggio go. Il valore di GOROOT non può essere modificato direttamente e può essere sovrascritto solo dalle variabili d'ambiente del sistema operativo.

sh
$ ls $GOROOT -1
api
bin
codereview.cfg
CONTRIBUTING.md
doc
go.env
lib
LICENSE
misc
PATENTS
pkg
README.md
SECURITY.md
src
test
VERSION

Nella directory radice ci sono diverse cartelle o file importanti

  • lib, contiene alcune dipendenze. Attualmente c'è solo una libreria con informazioni sul fuso orario di vari paesi del mondo, situata in $GOROOT/lib/time. I file binari compilati non conterranno queste informazioni sul fuso orario.

  • pkg, contiene alcune librerie di strumenti e file di intestazione. Ad esempio, il comando go tool cercherà i file binari della toolchain go nella directory $GOROOT/pkg/tool

  • bin, contiene file binari. Per impostazione predefinita, ci sono solo due file eseguibili: go e gofmt. $GOROOT/bin dovrebbe essere aggiunto alle variabili di sistema, altrimenti non sarà possibile utilizzare i comandi go.

  • src, contiene il codice sorgente go

  • VERSION, questo file contiene le informazioni sulla versione del linguaggio go

  • go.env, questo file è il file di configurazione env predefinito

GOPATH

Il valore predefinito di GOPATH è $HOME/go. Il valore di questa variabile d'ambiente specifica dove cercare i file importati durante l'analisi delle istruzioni import. Nei primi tempi, prima di gomod, GOPATH era utilizzato specificamente per memorizzare varie librerie di terze parti. La sua struttura è la seguente

sh
GOPATH=/home/user/go

/home/user/go/
    src/
        foo/
            bar/               (go code in package bar)
                x.go
            quux/              (go code in package main)
                y.go
    bin/
        quux                   (installed command)
    pkg/
        linux_amd64/
            foo/
                bar.a          (installed package object)

Dopo la nascita di gomod, GOPATH è diventato semplicemente un luogo per memorizzare le dipendenze scaricate con go get e i file binari scaricati e compilati con go install. Va notato che la posizione di GOPATH non può essere la stessa di GOROOT, altrimenti non avrà alcun effetto.

sh
$ go env GOBIN
warning: GOPATH set to GOROOT (/home/user/go) has no effect

Al momento della stesura di questo articolo, la versione del linguaggio go è arrivata a go1.21.3. Oltre a progetti molto antichi, quasi nessuno usa più gopath per gestire le dipendenze.

GOBIN

GOBIN è utilizzato per memorizzare i file binari eseguibili di terze parti scaricati e compilati con go install. Il suo valore predefinito è $GOPATH/bin. Come $GOROOT/bin, questa directory dovrebbe essere aggiunta alle variabili d'ambiente del sistema operativo, altrimenti non sarà possibile utilizzare i file binari nella directory GOBIN.

GOMODCACHE

GOMODCACHE indica la posizione in cui vengono memorizzate le dipendenze scaricate con go get. Il valore predefinito è $GOPATH/pkg/mod. Il formato di memorizzazione è il seguente

$GOMODCACHE/domain/username/project@verion

Nella stessa directory ci sarà anche una cartella chiamata sumdb, utilizzata per memorizzare le informazioni relative al database di checksum delle dipendenze.

GOCACHE

Memorizza le informazioni di cache per la compilazione. Il suo valore predefinito è $HOME/.cache/go-build. In questa directory verrà generato un file README.

sh
$ cat $(go env GOCACHE)/README
This directory holds cached build artifacts from the Go build system.
Run "go clean -cache" if the directory is getting too large.
Run "go clean -fuzzcache" to delete the fuzz cache.
See golang.org to learn more about Go.

Ogni build genera molti file. go memorizza questi file per riutilizzarli durante la compilazione successiva.

GOTEMPDIR

Utilizzato per i file temporanei generati durante la compilazione, ad esempio i file binari temporanei da eseguire con go run. Il suo valore predefinito è la directory temporaria specificata dal sistema operativo: /tmp su mac o linux, %TEMP% su windows. Può anche essere modificato in una posizione specificata dall'utente.

GO111MODULE

Questa variabile d'ambiente indica quale metodo utilizzare per gestire le dipendenze del progetto go. Ha tre valori disponibili

  • off: disattiva gomod, utilizza gopath e ignora tutti i file go.mod
  • on: utilizza gomod, non utilizza gopath (predefinito).
  • auto: rilevamento automatico. Se il file del progetto contiene go.mod, utilizza gomod per la gestione

TIP

Perché si chiama GO111MODULE e non semplicemente GOMODULE? Perché gomod è stato introdotto per la prima volta nella versione go1.11.

GOPROXY

Proxy del modulo go. Il valore predefinito è https://proxy.golang.org,direct. L'URL è separato da virgole. direct significa utilizzare direttamente VCS per saltare il proxy del modulo. Viene eseguito solo quando il primo non è accessibile. C'è anche un'opzione disponibile: off, che indica di proibire il download di qualsiasi modulo. Inoltre, GOPROXY può anche essere un indirizzo di file, ad esempio

GOPROXY=file://$(go env GOMODCACHE)/cache/download

Usando go get -x puoi vedere i comandi eseguiti durante il processo di download delle dipendenze e sapere se sta utilizzando il proxy.

sh
$ go get -x github.com/spf13/cast
# get https://goproxy.cn/github.com/@v/list
# get https://goproxy.cn/github.com/spf13/cast/@v/list
# get https://goproxy.cn/github.com/spf13/@v/list
# get https://goproxy.cn/github.com/spf13/@v/list: 404 Not Found (0.118s)
# get https://goproxy.cn/github.com/@v/list: 404 Not Found (0.197s)
# get https://goproxy.cn/github.com/spf13/cast/@v/list: 200 OK (0.257s)
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.info
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.info: 200 OK (0.013s)
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.mod
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.mod: 200 OK (0.015s)
# get https://goproxy.cn/sumdb/sum.golang.org/supported
# get https://goproxy.cn/sumdb/sum.golang.org/supported: 200 OK (0.064s)
# get https://goproxy.cn/sumdb/sum.golang.org/lookup/github.com/spf13/cast@v1.5.1
# get https://goproxy.cn/sumdb/sum.golang.org/lookup/github.com/spf13/cast@v1.5.1: 200 OK (0.014s)
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/0/x079/736
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/0/x079/736: 200 OK (0.016s)
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/0/x068/334
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/1/266
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/0/x068/334: 200 OK (0.023s)
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/1/266: 200 OK (0.028s)
go: downloading github.com/spf13/cast v1.5.1
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.zip
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.zip: 200 OK (0.024s)
go: added github.com/spf13/cast v1.5.1

L'utilizzo di un proxy del modulo può migliorare efficacemente la velocità di download del modulo. Per gli utenti in Cina, fondamentalmente senza un proxy non è possibile accedere al proxy ufficiale predefinito. Attualmente, i proxy di moduli di terze parti pubblici e affidabili sono i seguenti

  • https://proxy.golang.com.cn, open source e fornisce anche servizi enterprise
  • https://goproxy.cn, fornito e open source da Qiniu Cloud

C'è anche una soluzione open source per creare autonomamente un proxy di moduli: goproxy

GOSUMDB

GOSUMDB è utilizzato per impostare l'indirizzo del database di rilevamento del checksum della libreria di dipendenze. Il predefinito è sum.golang.org. Quando imposti un proxy, go accederà al database di checksum tramite il proxy.

GOPRIVATE

La variabile d'ambiente GOPRIVATE è utilizzata per impostare le librerie private. Le librerie corrispondenti non verranno verificate tramite sumdb e non passeranno attraverso il proxy. Verranno scaricate direttamente tramite VCS. Supporta impostazioni con caratteri jolly, separati da virgole. Come mostrato di seguito, tutte le dipendenze con suffisso corp.example.com e chiamate github.com/gohper/myproject non passeranno attraverso il proxy e sumdb.

GOPRIVATE=*.corp.example.com,github.com/gohper/myproject

Puoi anche impostare direttamente un utente o un'organizzazione specifica

GOPRIVATE=github.com/gopher,github.com/myorganization

GONOPROXY

Indica quali dipendenze non devono passare attraverso il proxy. Le regole sono le stesse di GOPRIVATE e sovrascrivono GOPRIVATE.

GONOSUMDB

Indica quali dipendenze non devono passare attraverso il database di checksum. Le regole sono le stesse di GOPRIVATE e sovrascrivono GOPRIVATE.

GOINSECURE

Indica quali dipendenze devono essere scaricate direttamente tramite VCS. Le regole sono le stesse di GOPRIVATE e vengono sovrascritte da GONOPROXY e GONOSUMDB.

GOVCS

Imposta il sistema di controllo versione per la gestione dei moduli. Il predefinito è public:git|hg,private:all. Puoi anche limitare VCS per domini specifici, ad esempio

GOVCS=github.com:git,evil.com:off,*:git|hg

Nella restrizione sopra, github può usare solo git, evil.com non è consentito e | può rappresentare più VCS. Se non si desidera applicare alcuna restrizione, è possibile impostare come segue

GOVCS=*:all

Se non si consente l'uso di alcun VCS, è possibile impostare come segue

GOVCS=*:off

GOWORK

Imposta se abilitare l'area di lavoro. Il predefinito è vuoto, cioè abilitato. Se impostato su off, non verrà abilitato e tutti i file go.work verranno ignorati.

GOTOOLDIR

Imposta la posizione della toolchain go da utilizzare. Il predefinito è $GOROOT/pkg/tool, dove si trova anche la toolchain predefinita.

GODEBUG

Imposta le opzioni di debug, controlla il comportamento di esecuzione di alcuni programmi go sotto forma di coppie chiave-valore, ad esempio

GODEBUG=http2client=0,http2server=0

Queste impostazioni sono convenienti quando si verificano cambiamenti incompatibili durante l'aggiornamento della versione, consentendo a go di tornare al comportamento precedente. Ad esempio, in 1.21 non è più consentita la situazione panic(nil). Per questo motivo, il team ufficiale di go ha registrato specificamente GODEBUG History. Visita GODEBUG per ulteriori dettagli.

CGO_ENABLED

Indica se abilitare cgo. Il predefinito è 1, cioè abilitato. Impostando su 0 si disattiva.

Le variabili d'ambiente sopra menzionate sono quelle più comunemente utilizzate. Per quelle meno comuni, come CGO, WASM, ecc., non verranno fornite ulteriori introduzioni. Se interessati, è possibile informarsi autonomamente.

build

Go supporta due tipi di compilatori: gccgo e gc. gcc è un vecchio compilatore C/C++ che supporta più linguaggi, incluso go. gc non significa garbage collector, ma go compiler. Il linguaggio go ha completato il bootstrap in go1.5. gc è un compilatore scritto completamente in linguaggio go e il suo codice sorgente si trova nel pacchetto cmd/compile. Poiché è completamente implementato in linguaggio go, è molto conveniente per comprendere e apprendere i suoi meccanismi interni. Per inciso, anche il debugger del linguaggio go è disponibile in due versioni: gdb e dlv. Il primo è un vecchio debugger C/C++ che supporta più linguaggi, incluso go. Il secondo è un debugger scritto in linguaggio go che offre un supporto più amichevole per il linguaggio go. Anche questo è open source e si consiglia di utilizzare quest'ultimo.

Il comando build viene utilizzato per compilare i file sorgente go in file binari eseguibili. Sperimentarai un'esperienza di compilazione estremamente rapida, che è una delle caratteristiche del linguaggio go.

sh
$ go build -h
usage: go build [-o output] [build flags] [packages]
Run 'go help build' for details.

Accetta tre parametri: uno è il percorso di output del file indicato dal flag -o, uno è il flag di compilazione build flags utilizzato per definire il comportamento di compilazione e l'ultimo è il pacchetto da compilare. Questo parametro deve essere posizionato per ultimo. Ecco un esempio semplice che non utilizza flag di compilazione.

sh
# Windows
$ go build -o .\bin\golearn.exe golearn

# macOS / Linux
$ go build -o ./bin/golearn golearn

./bin/golearn.exe indica il percorso di output e golearn indica il modulo da compilare. Può anche essere un file di ingresso o una cartella. Ad esempio, il semplice esempio seguente utilizza main.go come file di ingresso per la compilazione.

sh
# Windows
$ go build -o .\bin\golearn.exe main.go

# macOS / Linux
$ go build -o ./bin/golearn main.go

Durante la compilazione, ignorerà tutti i file che terminano con _test.go, poiché per convenzione questi sono file di test.

Inoltre, il comando build supporta numerosi flag di compilazione per controllare alcuni comportamenti durante la compilazione.

  • -x: produce istruzioni dettagliate durante il processo di compilazione
  • -n: simile a -x, ma la differenza è che produce solo queste istruzioni senza eseguirle effettivamente.
  • -v: produce i pacchetti compilati
  • -p: numero di processi concorrenti durante il processo di compilazione
  • -a: forza la ricompilazione, anche se è già aggiornata.
  • -compiler: specifica quale compilatore utilizzare, gccgo o gc. Quest'ultimo è un compilatore scritto in go.
  • -race: abilita il rilevamento delle race condition
  • -msan: abilita l'analisi della memoria
  • -asan: abilita l'analisi dell'indirizzo
  • -cover: abilita il rilevamento della copertura del codice
  • -buildmode: specifica la modalità di compilazione. Le opzioni sono archive, c-archive, c-shared, default, shared, exe, pie, plugin.
  • -pgo: specifica il file pgo
  • -trimpath: elimina il prefisso del percorso del file sorgente. Ad esempio, il percorso relativo /var/lib/go/src/main.go dopo l'eliminazione avrà solo il percorso relativo al percorso del modulo /main.go quando ottenuto tramite runtime durante l'esecuzione. Abilitando questa opzione, il tempo di compilazione aumenterà significativamente, circa del 20-40%, a seconda del numero di file.
  • -toolexec: alcuni comandi go da eseguire prima della compilazione, nel formato -toolexec 'cmd args'.
  • -gcflags: specifica alcuni tag per il compilatore gc
  • -gccgoflags: specifica alcuni tag per il compilatore gccgo
  • -ldflags: specifica alcuni tag per lo strumento di link

Per alcuni parametri di passaggio come ldflags, è possibile passare parametri come "-help" per ottenere i possibili valori. Ad esempio

sh
$ go build -ldflags -help
usage: link [options] main.o
  -B note
        add an ELF NT_GNU_BUILD_ID note when using ELF
  -E entry
        set entry symbol name
......

Quelli sopra menzionati sono i più comunemente utilizzati. Per altri meno comuni, è possibile informarsi autonomamente.

gcflags

Tramite gcflags è possibile passare alcuni parametri al compilatore gc per controllare comportamenti specifici. Il formato di utilizzo è -gcflags="pattern=args list", dove args list è l'elenco dei parametri e pattern è l'ambito di applicazione. Ci sono i seguenti valori disponibili

  • main, il percorso del pacchetto di primo livello in cui si trova il file di ingresso
  • all, il modulo corrente e tutte le sue dipendenze nella modalità corrente
  • std, libreria standard
  • cmd, tutti i file sorgente nel pacchetto cmd
  • Caratteri jolly, come ., ./..., cmd/....

La regola pattern si applica a tutti i flag che supportano questo formato, come ldflags. È possibile visualizzare i valori disponibili dei parametri con il seguente comando

sh
$ go build -gcflags -help
usage: compile [options] file.go...
  -%    debug non-static initializer
  -+    compile runtime
  -B    disable bounds checking
  -C    disable printing of column number in error messages
  -D path
        set relative path for local imports
  -E    debug symbol export
  -I directory
        add directory to import search path
  -K    debug missing line numbers
  -L    also show actual source file location for errors affected by //line directives
  -N    disable optimizations
  -S    print assembly listing
  -V    print version and exit
  -W    debug parse tree after typechecking
  ......

Di seguito sono presentati alcuni parametri comunemente utilizzati

  • -S: produce la forma assembly del codice
  • -N: disattiva l'ottimizzazione della compilazione
  • -m: produce le decisioni di ottimizzazione
  • -l: disattiva l'inlining delle funzioni
  • -c: numero di processi concorrenti per la compilazione
  • -dwarf: genera flag DWARF

Ad esempio, se si desidera visualizzare la forma assembly del codice, è possibile utilizzare il parametro -S e disattivare l'ottimizzazione e l'inlining per ripristinare la sua forma originale. Come segue

sh
$ go build -trimpath -gcflags="-N -l -S" main.go
main.main STEXT size=171 args=0x0 locals=0x58 funcid=0x0 align=0x0
        0x0000 00000 (./main.go:9)      TEXT    main.main(SB), ABIInternal, $88-0
        0x0000 00000 (./main.go:9)      CMPQ    SP, 16(R14)
        0x0004 00004 (./main.go:9)      PCDATA  $0, $-2
        0x0004 00004 (./main.go:9)      JLS     161
        0x000a 00010 (./main.go:9)      PCDATA  $0, $-1
        0x000a 00010 (./main.go:9)      PUSHQ   BP
        0x000b 00011 (./main.go:9)      MOVQ    SP, BP
        0x000e 00014 (./main.go:9)      SUBQ    $80, SP
        0x0012 00018 (./main.go:9)      FUNCDATA        $0, gclocals·J5F+7Qw7O7ve2QcWC7DpeQ==(SB)
        0x0012 00018 (./main.go:9)      FUNCDATA        $1, gclocals·bDfKCdmtOiGIuJz/x+yQyQ==(SB)
        0x0012 00018 (./main.go:9)      FUNCDATA        $2, main.main.stkobj(SB)
        0x0012 00018 (./main.go:10)     MOVUPS  X15, main..autotmp_0+40(SP)
        0x0018 00024 (./main.go:10)     LEAQ    main..autotmp_0+40(SP), CX
        0x001d 00029 (./main.go:10)     MOVQ    CX, main..autotmp_2+32(SP)

ldflags

Tramite ldflags è possibile passare alcuni parametri al linker per controllare comportamenti specifici. È possibile visualizzare tutti i valori disponibili di ldflags con il seguente comando, che sono circa una ventina.

sh
$ go build -ldflags -help
usage: link [options] main.o
  -B note
        add an ELF NT_GNU_BUILD_ID note when using ELF
  -E entry
        set entry symbol name
  -H type
        set header type
  -I linker
        use linker as ELF dynamic linker
  -L directory
        add specified directory to library path
  -R quantum
        set address rounding quantum (default -1)
  -T int
        set the start address of text symbols (default -1)
  -V    print version and exit
  -X definition
        add string value definition of the form importpath.name=value
  -a    no-op (deprecated)
  .....

Il parametro -X di ldflags è una funzione molto pratica. Permette di definire il valore di variabili stringa di pacchetti specificati durante il linking. Grazie a questa funzione, possiamo iniettare comodamente alcune metainformazioni durante la compilazione. Ed è solo una variabile, quindi è anche comodo da ottenere durante l'esecuzione. Ecco un esempio semplice.

go
package main

import "fmt"

var (
  Version string
)

func main() {
  fmt.Println(Version)
}

Esegui il comando

sh
go build -ldflags "-X main.Version=$(git describe --always)" main.go

Dopo l'esecuzione, verrà prodotto il checksum sha1 del commit git.

5e3fd7a

Altri parametri pratici includono

  • -w: non genera DWARF, che è un'informazione conveniente per il debug del codice sorgente.
  • -s: disattiva la tabella dei simboli

Questi due vengono solitamente utilizzati insieme e possono ridurre significativamente le dimensioni del file binario compilato, circa del 40%-50%. Lo svantaggio è anche evidente: non è possibile eseguire il debug. Ecco un esempio.

sh
$ go build -ldflags="-w -s" main.go

Compilazione incrociata

La compilazione del linguaggio go ha due caratteristiche principali: la prima è la velocità, l'altra è la compilazione incrociata. La compilazione incrociata si riferisce alla possibilità di compilare localmente il codice obiettivo di altri sistemi, ad esempio compilare file binari per linux o darwin su windows, e viceversa. Molti linguaggi supportano la compilazione incrociata, il che non è nulla di straordinario, ma la compilazione incrociata del linguaggio go è molto semplice, richiede solo i seguenti passaggi

  1. Imposta la variabile d'ambiente GOOS per selezionare il sistema operativo di destinazione
  2. Imposta la variabile d'ambiente GOARCH per selezionare l'architettura CPU di destinazione
  3. Utilizza go build per compilare come al solito

L'intero processo è molto breve, non richiede strumenti o configurazioni aggiuntive e la velocità è veloce come al solito. Come mostrato di seguito

makefile
build_linux:
	SET CGO_ENABLED=0
	SET GOOS="linux"
	SET GOARCH="amd64"
	go build -o golearn  main.go

build_mac:
	SET CGO_ENABLED=0
	SET GOOS="darwin"
	SET GOARCH="amd64"
	go build -o golearn main.go

build_win:
	SET CGO_ENABLED=0
	SET GOOS="win"
	SET GOARCH="amd64"
	go build -o golearn.exe main.go

.PHONY: build_linux \
    build_mac \
    build_win

Il primo passaggio SET CGO_ENABLED=0 disabilita cgo. Una volta che il tuo codice utilizza cgo, non è possibile utilizzare normalmente la compilazione incrociata. Il secondo passaggio SET GOOS imposta il sistema di destinazione. Le opzioni sono linux, darwin, windwos, netbsd. Il terzo passaggio imposta l'architettura CPU, SET GOARCH. Le opzioni sono amd64, 386, arm, ppc64. L'ultimo passaggio è compilare come al solito.

Controllo della compilazione

Il comando build può raggiungere l'obiettivo di controllare la compilazione tramite tags. Esistono sotto forma di istruzioni nel codice sorgente. Ecco un esempio, il file product.go

go
// +build product

package main

import "fmt"

func main() {
  fmt.Println("product")
}

Il file debug.go

go
// +build debug

package main

import "fmt"

func main() {
  fmt.Println("debug")
}

Entrambi hanno un'istruzione // +build che indica in quali circostanze verranno compilati. Il formato di base è

go
// +build tag1 tag2

package pkg_name

Ci sono alcune regole che devono essere seguite

  1. Deve esserci uno spazio tra // e +build
  2. Deve essere posizionato sopra la dichiarazione del pacchetto
  3. Deve esserci una riga vuota tra esso e la dichiarazione del pacchetto

Inoltre, può raggiungere lo scopo del controllo logico attraverso semplici spaziature: lo spazio indica OR, la virgola indica AND, ! indica NOT. Ad esempio, il seguente esempio

go
// +build windows linux

package pkg_name

Indica che il file corrente verrà compilato su piattaforme windows o linux.

go
// +build windows,amd64,!cgo linux,i386,cgo

package pkg_name

Questo esempio indica che verrà compilato solo su piattaforma windows con architettura amd64 e senza cgo abilitato, oppure su piattaforma linux con architettura i386 e con cgo abilitato. Se semplicemente non desideri che un file partecipi alla compilazione, puoi utilizzare ignore.

go
// +build ignore

package pkg_name

Possono anche esistere istruzioni su più righe

go
// +build windows
// +build amd64

package pkg_name

Le istruzioni su più righe vengono elaborate in modalità AND. Per tag come piattaforma e architettura, go li passerà automaticamente durante la compilazione. Possiamo anche passare tag personalizzati. Prendiamo i due file iniziali come esempio

sh
$ go build -tags="debug" . && ./golearn.exe
debug

$ go build -tags="product" . && ./golearn.exe
product

Come puoi vedere, passando tag diversi si ottengono output diversi. L'obiettivo del controllo della compilazione è raggiunto.

run

Il comando run, come build, compilerà il codice sorgente. La differenza è che il comando run eseguirà direttamente dopo la compilazione. Il comando run, per accelerare la velocità di compilazione, non genera informazioni di debug durante il processo di compilazione, quindi non supporta il debug e genera solo un file binario temporaneo, solitamente memorizzato nella directory GOTMEPDIR, ad esempio /temp/go-build2822241271/b001/exe/main.exe.

sh
$ go run -h
usage: go run [build flags] [-exec xprog] package [arguments...]
Run 'go help run' for details.

Supporta anche i flag di compilazione del comando build e fornisce un parametro -exec per indicare quale programma utilizzare per eseguire il file binario. [arguments...] si riferisce ai parametri di esecuzione del programma. Ecco un esempio

go
package main

import (
  "fmt"
  "os"
)

var (
  Version string
)

func main() {
  fmt.Println(Version)
  fmt.Println(os.Args[1:])
}

Esegui con go run

sh
$ go run -ldflags="-X main.Version=$(git describe --always)" main.go hello
5e3fd7a
[hello]

Nel complesso, l'utilizzo non è molto diverso da go build, quindi non mi dilungherò ulteriormente.

tool

Il comando tool non ha alcuna funzione di per sé. Il suo scopo è chiamare direttamente gli strumenti nella directory cmd/. Ad esempio, cmd/compile è il compilatore integrato. Tramite go tool è possibile chiamare direttamente questi strumenti senza dover eseguire manualmente i file binari di questi strumenti.

sh
$ go tool -h
usage: go tool [-n] command [args...]

Usa il parametro -n per stampare tutti i parametri di comando supportati

sh
$ go tool -n
addr2line
asm
buildid
cgo
compile
covdata
cover
doc
fix
link
nm
objdump
pack
pprof
test2json
trace
vet

Questi strumenti sono memorizzati nella directory GOROOT/pkg/tool e sono raggruppati in base al sistema operativo e all'architettura CPU. Come segue.

sh
$ ls $GOROOT/pkg/tool/windows_amd64/ -1
addr2line.exe*
asm.exe*
buildid.exe*
cgo.exe*
compile.exe*
covdata.exe*
cover.exe*
doc.exe*
fix.exe*
link.exe*
nm.exe*
objdump.exe*
pack.exe*
pprof.exe*
test2json.exe*
trace.exe*
vet.exe*

Utilizza il formato go doc cmd/command per visualizzare l'utilizzo di ogni comando. Ad esempio

sh
$ go doc cmd/compile
Usage:

    go tool compile [flags] file...

The specified files must be Go source files and all part of the same package.
The same compiler is used for all target operating systems and architectures.
The GOOS and GOARCH environment variables set the desired target.

Flags:

    -D path
        Set relative path for local imports.
    -I dir1 -I dir2
        Search for imported packages in dir1, dir2, etc,
        after consulting $GOROOT/pkg/$GOOS_$GOARCH.
    -L
        Show complete file path in error messages.
...

I flag supportati da cmd/compile sono gli stessi parametri supportati da gcflags menzionati in precedenza. La differenza tra go tool compile e go build è che il primo è solo responsabile della compilazione e può accettare solo file come parametri. Il secondo può accettare cartelle, pacchetti e file come parametri e non si limita a compilare il codice sorgente, ma si occupa anche di collegare i file, eliminare i file inutili, ecc. Il primo è una parte del secondo. Possiamo stampare i comandi eseguiti durante il processo di build

sh
$ go build -n main.go

#
# internal/goarch
#

mkdir -p $WORK\b004\
cat >$WORK\b004\importcfg << 'EOF' # internal
# import config
EOF
"/golang/pkg/tool/windows_amd64/compile.exe" -o "$WORK/b004/_pkg_.a" -trimpath "$WORK/b004=>" -p internal/goarch -std -+ -complete -buildid 3gunEkUExGdhOPa2rFsh/3gunEkUExGdhOPa2rFsh -goversion go1.21.0 -c=4 -nolocalimports -importcfg "$WORK/b004/importcfg" -pack "/golang/src/internal/goarch/goarch.go" "/golang/src/internal/goarch/goarch_amd64.go" "/golang/src/internal/goarch/zgoarch_amd64.go"
"/golang/pkg/tool/windows_amd64/buildid.exe" -w "$WORK/b004/_pkg_.a" # internal
...

Nel processo puoi vedere che c'è /golang/pkg/tool/windows_amd64/compile.exe, che è la chiamata al compilatore. Oltre a compile, ci sono molti altri strumenti che possono essere chiamati. Molti comandi go sono in realtà i loro alias.

clean

Il comando clean viene utilizzato per eliminare i file oggetto generati durante il processo di compilazione

sh
$ go clean -h
usage: go clean [clean flags] [build flags] [packages]
Run 'go help clean' for details.

Supporta i seguenti flag

  • -i: elimina i file archivio o i file binari corrispondenti
  • -n: stampa i comandi da eseguire durante il processo di pulizia ma non li esegue effettivamente
  • -x: stampa ed esegue i comandi da eseguire durante il processo di pulizia
  • -r: esegue la pulizia ricorsivamente tramite import path
  • -cache: elimina tutta la cache generata da go build
  • -testcache: elimina tutta la cache di test generata
  • -modcache: elimina tutta la cache dei moduli scaricati
  • -fuzzcache: elimina la cache generata da fuzz test.

Quando si utilizza go tool compile, si chiama direttamente il comando del compilatore e non si eseguono molte operazioni di pulizia come go build, generando così file oggetto. Ad esempio, eseguendo il seguente comando

sh
go tool compile -N -S -l main.go

verrà generato un file chiamato main.o. Utilizza il comando go clean per eliminarlo. Oppure usa il parametro -n per stampare i comandi da eseguire.

sh
$ go clean -n
rm -f golearn golearn.exe golearn golearn.exe golearn.test golearn.test.exe golearn.test golearn.test.exe api api.exe main main.exe

Elimina la cache di compilazione. Eliminerà la cache di compilazione generata nella directory GOCACHE

sh
$ go clean -cache -n
rm -r /cache/00 /cache/01 /cache/02

Elimina la cache generata da fuzz test. Queste cache sono memorizzate per impostazione predefinita nella directory GOCACHE/fuzz/

sh
$ go clean -fuzzcache -n
rm -rf /cache/fuzz

fix

Al momento della stesura di questo articolo, il linguaggio go esiste da dieci anni. Durante il processo continuo di aggiornamento e modifica del linguaggio, è inevitabile che si verifichino incompatibilità dovute a cambiamenti nelle API. Il comando fix è nato per questo scopo. Rileverà le API obsolete nei file sorgente e le sostituirà con le nuove API.

sh
$ go fix -h
usage: go fix [-fix list] [packages]
Run 'go help fix' for details.

Supporta cartelle, nomi di file e directory come parametri. Accetta il flag -fix per passare parametri che indicano quale tipo di modifica eseguire. È possibile visualizzare i valori disponibili tramite il comando go tool fix -help

sh
$ go tool fix -help
usage: go tool fix [-diff] [-r fixname,...] [-force fixname,...] [path ...]
  -diff
        display diffs instead of rewriting files
  -force string
        force these fixes to run even if the code looks updated
  -go string
        go language version for files
  -r string
        restrict the rewrites to this comma-separated list

Available rewrites are:

buildtag
        Remove +build comments from modules using Go 1.18 or later

cftype
        Fixes initializers and casts of C.*Ref and JNI types

context
        Change imports of golang.org/x/net/context to context

egl
        Fixes initializers of EGLDisplay

eglconf
        Fixes initializers of EGLConfig

gotypes
        Change imports of golang.org/x/tools/go/{exact,types} to go/{constant,types}

jni
        Fixes initializers of JNI's jobject and subtypes

netipv6zone
        Adapt element key to IPAddr, UDPAddr or TCPAddr composite literals.

        https://codereview.appspot.com/6849045/

printerconfig
        Add element keys to Config composite literals.

Ecco un esempio. Il codice sorgente utilizza il pacchetto golang.org/x/net/context

sh
package main

import (
  "fmt"
  "golang.org/x/net/context"
)

func main() {
  background := context.Background()
  fmt.Println(background.Err())
}

Correggi con go fix per sostituirlo con il pacchetto context della libreria standard. Puoi utilizzare il seguente comando per eseguire la sostituzione

sh
$ go fix -fix context main.go

Puoi anche non sostituire e vedere le variazioni del file prima e dopo.

sh
$ go tool fix -r context -diff  main.go
main.go: fixed context
diff main.go fixed/main.go
--- main.go
+++ fixed/main.go
@@ -1,8 +1,8 @@
 package main

 import (
+       "context"
        "fmt"
-       "golang.org/x/net/context"
 )

 func main() {

Il linguaggio go è nato da oltre dieci anni e ha solo nove parametri di sostituzione disponibili. Questo mostra che la compatibilità è stata mantenuta abbastanza bene.

fmt

Il comando fmt è lo strumento di formattazione integrato del linguaggio go, utilizzato per formattare i file di codice sorgente go.

sh
$ go fmt -h
usage: go fmt [-n] [-x] [packages]
Run 'go help fmt' for details.

Visualizza la documentazione dettagliata con il comando go doc gofmt

sh
$ go doc cmd/gofmt
Gofmt formats Go programs. It uses tabs for indentation and blanks for
alignment. Alignment assumes that an editor is using a fixed-width font.

Usage:

    gofmt [flags] [path ...]

The flags are:

    -d
        Do not print reformatted sources to standard output.
        If a file's formatting is different than gofmt's, print diffs
        to standard output.
    -e
        Print all (including spurious) errors.
    -l
        Do not print reformatted sources to standard output.
        If a file's formatting is different from gofmt's, print its name
        to standard output.
    -r rule
        Apply the rewrite rule to the source before reformatting.
    -s
        Try to simplify code (after applying the rewrite rule, if any).
    -w
        Do not print reformatted sources to standard output.
        If a file's formatting is different from gofmt's, overwrite it
        with gofmt's version. If an error occurred during overwriting,
        the original file is restored from an automatic backup.

gofmt utilizza tab per l'indentazione e spazi per l'allineamento. Per impostazione predefinita, il codice formattato verrà prodotto sull'output standard, non sovrascrivendo il file originale. Il comando go fmt utilizza effettivamente il comando gofmt, che è un file binario indipendente situato nella directory GOROOT/bin.

sh
$ ls $GOROOT/bin -1
go.exe*
gofmt.exe*

Aggiungendo il flag -n al comando go fmt puoi sapere quali comandi verranno eseguiti.

sh
$ go fmt main.go
/golang/bin/gofmt.exe -l -w main.go

Come puoi vedere, go fmt è in realtà un alias di gofmt -l -w. Il comando gofmt ha i seguenti parametri

  • -d: produce le differenze del file prima e dopo la formattazione
  • -e: produce tutti gli errori
  • -l: produce il nome del file che è stato modificato
  • -r: applica le regole di formattazione
  • -s: tenta di semplificare il codice
  • -w: sovrascrive il file sorgente. Se si verifica un errore, ripristina il backup

Supponiamo ora di avere il seguente file sorgente

go
$ cat main.go
package main

import "fmt"

func main() {
fmt.Println("hello world!")}

Puoi visualizzare le variazioni con il parametro -d

sh
$ gofmt -d main.go
diff main.go.orig main.go
--- main.go.orig
+++ main.go
@@ -3,5 +3,5 @@
 import "fmt"

 func main() {
-fmt.Println("hello world!")}
-
+       fmt.Println("hello world!")
+}

Il parametro -l produrrà il nome del file che verrà modificato

$ gofmt -l .
main.go

Se ci sono errori di sintassi, il parametro -e può produrre output più dettagliati

sh
$ gofmt -d -e main.go
main.go:6:27: missing ',' in argument list
main.go:6:28: expected operand, found newline
main.go:7:2: expected ')', found 'EOF'
main.go:7:2: expected ';', found 'EOF'
main.go:7:2: expected ';', found 'EOF'
main.go:7:2: expected '}', found 'EOF'
main.go:7:2: missing ',' in argument list

-w applicherà le modifiche al file sorgente

sh
$ gofmt -l -w .
main.go

$ cat main.go
package main

import "fmt"

func main() {
        fmt.Println("hello world!")
}

Puoi notare che, come strumento di formattazione, gofmt non fornisce alcuna configurazione personalizzata. Al contrario, il formatter prettify dedicato all'abbellimento del codice js fornisce numerose configurazioni per la formattazione del codice. Questo riflette l'atteggiamento ufficiale di go: non vuoi personalizzazioni, il codice di tutti dovrebbe avere lo stesso stile. Almeno c'è un vantaggio: non devi adattarti alle abitudini degli altri quando leggi il codice. Tuttavia, mantiene effettivamente un elemento personalizzabile: le regole di sostituzione del codice formattato. Le regole sono personalizzabili e il formato è il seguente

pattern -> replacement

Ad esempio, per rimuovere le parentesi ridondanti

(a) -> a

Visualizza le variazioni del file

sh
$ gofmt -r "(a) -> a" -d -l .
main.go
diff main.go.orig main.go
--- main.go.orig
+++ main.go
@@ -3,5 +3,5 @@
 import "fmt"

 func main() {
-       fmt.Println(("hello world!"))
+       fmt.Println("hello world!")
 }

Come puoi vedere, gofmt rimuoverà le parentesi ridondanti.

get

Il comando get è assolutamente uno dei più utilizzati durante lo sviluppo go. Il suo scopo è scaricare il codice sorgente del pacchetto specificato nella directory corrispondente a GOMODCACHE.

sh
$ go get -h
usage: go get [-t] [-u] [-v] [build flags] [packages]
Run 'go help get' for details.
  • -u: tenta di aggiornare la versione secondaria e la versione patch del pacchetto. Se comporta un cambiamento di versione principale, come v1->v2, non verrà aggiornato.
  • -t: aggiorna la versione delle dipendenze nei test
  • -v: produce i pacchetti compilati. In realtà è uno dei parametri di build flags

Nei tempi antichi, go get aveva una funzione simile a go install: scaricava e compilava questi pacchetti. Tuttavia, con la nascita e il perfezionamento dei moduli go, questa funzione è stata gradualmente abbandonata. Ora il comando get è più comunemente utilizzato per scaricare e risolvere le dipendenze dei moduli go. Quindi puoi vedere che il comando go get supporta anche flag di compilazione come build flags. E se provi a utilizzare go get al di fuori di un modulo come faresti con go install, ti avviserà che questo utilizzo è deprecato.

sh
$ go get github.com/wire/wire
go: go.mod file not found in current directory or any parent directory.
        'go get' is no longer supported outside a module.
        To build and install a command, use 'go install' with a version,
        like 'go install example.com/cmd@latest'
        For more information, see https://golang.org/doc/go-get-install-deprecation
        or run 'go help get' or 'go help install'.

Non si sa perché questi siano ancora mantenuti nella descrizione della documentazione. Esaminando il codice sorgente del comando get, scoprirai che ha mantenuto quei flag precedenti.

go
var (
  getD        = CmdGet.Flag.Bool("d", true, "")
  getF        = CmdGet.Flag.Bool("f", false, "")
  getFix      = CmdGet.Flag.Bool("fix", false, "")
  getM        = CmdGet.Flag.Bool("m", false, "")
  getT        = CmdGet.Flag.Bool("t", false, "")
  getU        upgradeFlag
  getInsecure = CmdGet.Flag.Bool("insecure", false, "")
  // -v is cfg.BuildV
)

Tornando al punto, il comando get scaricherà il codice sorgente del pacchetto specificato nella directory globale delle dipendenze locale, ovvero la directory corrispondente a GOCACHE, e registrerà le informazioni nei file go.mod e go.sum. Il primo è responsabile della registrazione della versione e il secondo registra il checksum sha1 per garantire la sicurezza. Il comando get si basa effettivamente su VCS, ovvero il sistema di controllo versione locale. Supporta complessivamente i seguenti

  • git
  • hg (Mercurial)
  • bzr (Bazaar)
  • svn
  • fossil

Tra questi, per impostazione predefinita supporta solo git e hg. È possibile configurare in GOVCS. Il formato è il seguente

GOVCS=github.com:git,example.com:hg,*:git|hg,*:all

GOVCS supporta solo git e hg come VCS. Gli altri tre devono essere configurati in GOPRIVATE.

Il comando go get ha complessivamente i seguenti utilizzi. Puoi passare direttamente l'indirizzo della dipendenza come parametro

sh
$ go get golang.org/x/net

Puoi anche specificare una versione

sh
$ go get golang.org/x/net@0.17.0

Specificare l'ultima versione

sh
$ go get golang.org/x/net@latest

Tentare di aggiornare la versione

sh
$ go get -u golang.org/x/net

Rimuovere una dipendenza

sh
$ go get golang.org/x/net@none

Questi sopra sono utilizzati per gestire dipendenze ordinarie. Può anche essere utilizzato per gestire dipendenze non ordinarie, come aggiornare la versione del linguaggio go

sh
$ go get go@latest
go: updating go.mod requires go >= 1.21.3; switching to go1.21.3
go: downloading go1.21.3 (windows/amd64)
go: upgraded go 1.21.0 => 1.21.3

Può anche essere utilizzato per aggiornare la versione della toolchain go

sh
$ go get toolchain@latest

Quando utilizzi go get per aggiornare le versioni di go e della toolchain, installeranno la nuova versione di go nella directory GOMODCACHE/golang.org/

sh
$ ls $(go env GOMODCACHE)/golang.org -1
'toolchain@v0.0.1-go1.21.3.windows-amd64'/
x/

A questo punto, modificando manualmente GOROOT puoi passare alla versione specificata.

install

Il comando install è simile al comando get. Entrambi sono utilizzati per scaricare dipendenze di terze parti. La differenza è che il comando get scarica il codice sorgente, mentre il comando install compilerà il codice sorgente in un file binario eseguibile per la macchina locale. Il percorso di memorizzazione del file binario è prima nella directory GOBIN, poi in GOPATH/bin. La funzione principale di questo comando è scaricare alcuni strumenti da riga di comando pubblici di terze parti. Grazie alla velocità di compilazione e alla portabilità del linguaggio go, non è necessario scaricare file binari, ma scaricare direttamente il codice sorgente e compilarlo localmente.

sh
$ go install -h
usage: go install [build flags] [packages]
Run 'go help install' for details.

Il comando install accetta flag di compilazione e nomi di pacchetti come parametri. Con gomod abilitato, il nome del pacchetto deve includere il numero di versione. Ad esempio, per scaricare il debugger delve

sh
$ go install -x github.com/go-delve/delve/cmd/dlv@latest
# get https://goproxy.cn/github.com/@v/list
# get https://goproxy.cn/github.com/go-delve/delve/cmd/@v/list
# get https://goproxy.cn/github.com/go-delve/delve/cmd/dlv/@v/list
# get https://goproxy.cn/github.com/go-delve/delve/@v/list
# get https://goproxy.cn/github.com/go-delve/@v/list
# get https://goproxy.cn/github.com/@v/list: 404 Not Found (0.014s)
# get https://goproxy.cn/github.com/go-delve/delve/cmd/@v/list: 404 Not Found (0.027s)
# get https://goproxy.cn/github.com/go-delve/delve/cmd/dlv/@v/list: 404 Not Found (0.027s)
# get https://goproxy.cn/github.com/go-delve/delve/@v/list: 200 OK (0.027s)
# get https://goproxy.cn/github.com/go-delve/@v/list: 404 Not Found (0.027s)
WORK=/home/user/tmp/go-build2033992495
mkdir -p $WORK/b001/
cat >/home/user/tmp/go-build2033992495/b001/importcfg.link << 'EOF' # internal
packagefile github.com/go-delve/delve/cmd/dlv=/home/user/.cache/go-build/f1/f11d552287458c0fce625abe50bf928c487064c36bbb1251ad8b1968772c3e4b-d
......
......
mkdir -p /home/wyh/gomod/bin/
mv $WORK/b001/exe/a.out /home/wyh/gomod/bin/dlv
rm -r $WORK/b001/

Innanzitutto scaricherà il codice sorgente nel percorso memorizzato in GOMODCACHE, proprio come il comando get. Quindi passerà alla directory di lavoro temporanea per compilarlo. Dopo aver completato la compilazione, sposterà il file binario nella directory GOPATH/bin e infine eliminerà la cartella temporanea. Il comando install ha anche una limitazione: il pacchetto scaricato deve essere il pacchetto di ingresso del progetto, ovvero deve contenere il file di ingresso main.go. Altrimenti, ti avviserà che non può essere installato. Ad esempio, utilizzando go install per scaricare gin

sh
$ go install -x github.com/gin-gonic/gin@latest
# get https://goproxy.cn/github.com/@v/list
# get https://goproxy.cn/github.com/gin-gonic/gin/@v/list
# get https://goproxy.cn/github.com/gin-gonic/@v/list
# get https://goproxy.cn/github.com/@v/list: 404 Not Found (0.022s)
# get https://goproxy.cn/github.com/gin-gonic/gin/@v/list: 200 OK (0.027s)
# get https://goproxy.cn/github.com/gin-gonic/@v/list: 404 Not Found (0.028s)
package github.com/gin-gonic/gin is not a main package

gin è una libreria di dipendenze per framework web, non uno strumento da riga di comando, quindi naturalmente non ha un file di ingresso e l'installazione fallirà.

list

Il comando list elencherà i pacchetti nella posizione specificata, uno per riga, e supporta l'output formattato personalizzato. Supporta molti parametri. Il prerequisito per il suo utilizzo è che deve essere all'interno di un progetto che supporta gomod.

sh
$ go list -h
usage: go list [-f format] [-json] [-m] [list flags] [build flags] [packages]
Run 'go help list' for details.

I parametri supportati sono i seguenti

  • -f: parametro di formattazione
  • -json: output in formato json
  • -compiled: mostra tutti i pacchetti che verranno compilati dal compilatore
  • -deps: mostra il nome di ogni pacchetto e di ogni sua dipendenza
  • -test: mostra il pacchetto di test di ogni pacchetto
  • -e: produce normalmente quando incontra pacchetti con errori
  • -find: non analizza le relazioni di dipendenza di questi pacchetti
  • -export: quando si utilizza questo parametro, imposta il valore del campo Package.Export della struct sul file contenente le informazioni di esportazione più recenti del pacchetto specificato e imposta il valore del campo Package.BuildID sul BuildID del pacchetto. Principalmente utilizzato per l'output formattato.

Parametri di informazioni sul modulo

  • -m: produce moduli invece di pacchetti

  • -versions: mostra tutte le informazioni disponibili di un modulo

  • -retracted: mostra le versioni ritirate di un modulo

Il parametro [packages] può essere un nome di pacchetto specificato o una cartella. Può anche essere all, che indica ovunque. Quando si utilizza il parametro -m, all indica tutte le dipendenze citate dal modulo corrente.

Ad esempio, il file corrente contiene solo un file main.go con una sola riga di codice che produce "hello world". Dopo aver eseguito go list -deps ., produce tutti i pacchetti di dipendenza dal progetto corrente a fmt e alle sue dipendenze.

bash
$ ls
go.mod  go.sum  main.go

$ cat main.go
package main

import "fmt"

func main() {
        fmt.Println("hello world")
}

$ go list -deps .
internal/goarch
unsafe
internal/abi
internal/unsafeheader
internal/cpu
internal/bytealg
internal/coverage/rtcov
internal/godebugs
internal/goexperiment
internal/goos
runtime/internal/atomic
runtime/internal/math
runtime/internal/sys
runtime
......
......
path
io/fs
os
fmt
golearn

Oppure produce tutte le dipendenze del modulo nel progetto corrente

bash
$ go list -m all
golearn
cloud.google.com/go v0.26.0
github.com/246859/containers v0.0.1
github.com/246859/river v0.1.0 => D:\WorkSpace\Code\riverdb
github.com/BurntSushi/toml v0.3.1
github.com/Jleagle/steam-go v0.0.0-20230725082712-1053b441b1f2
github.com/Jleagle/unmarshal-go v0.0.0-20210227002040-694f544f9265
github.com/KyleBanks/depth v1.2.1
github.com/Microsoft/go-winio v0.6.1
github.com/PuerkitoBio/purell v1.1.1
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578
github.com/andeya/ameda v1.5.3
github.com/andeya/goutil v1.0.1
...

format

L'output del comando list è per riga. Ogni riga di output è un pacchetto. L'ufficio fornisce il parametro -f per personalizzare il formato di output della riga. Il valore accettato è la sintassi del template definita dal pacchetto del motore template template/text. Ad esempio, il seguente esempio

sh
-f "package {{ .Dir }} {{ .Name }}"

Ogni pacchetto iterato verrà passato nella forma della seguente struct. Tutti i campi di questa struct possono essere utilizzati come parametri del template.

go
type Package struct {
    Dir            string   // directory containing package sources
    ImportPath     string   // import path of package in dir
    ImportComment  string   // path in import comment on package statement
    Name           string   // package name
    Doc            string   // package documentation string
    Target         string   // install path
    Shlib          string   // the shared library that contains this package (only set when -linkshared)
    Goroot         bool     // is this package in the Go root?
    Standard       bool     // is this package part of the standard Go library?
    Stale          bool     // would 'go install' do anything for this package?
    StaleReason    string   // explanation for Stale==true
    Root           string   // Go root or Go path dir containing this package
    ConflictDir    string   // this directory shadows Dir in $GOPATH
    BinaryOnly     bool     // binary-only package (no longer supported)
    ForTest        string   // package is only for use in named test
    Export         string   // file containing export data (when using -export)
    BuildID        string   // build ID of the compiled package (when using -export)
    Module         *Module  // info about package's containing module, if any (can be nil)
    Match          []string // command-line patterns matching this package
    DepOnly        bool     // package is only a dependency, not explicitly listed
    DefaultGODEBUG string  // default GODEBUG setting, for main packages

    // Source files
    GoFiles           []string   // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
    CgoFiles          []string   // .go source files that import "C"
    CompiledGoFiles   []string   // .go files presented to compiler (when using -compiled)
    IgnoredGoFiles    []string   // .go source files ignored due to build constraints
    IgnoredOtherFiles []string // non-.go source files ignored due to build constraints
    CFiles            []string   // .c source files
    CXXFiles          []string   // .cc, .cxx and .cpp source files
    MFiles            []string   // .m source files
    HFiles            []string   // .h, .hh, .hpp and .hxx source files
    FFiles            []string   // .f, .F, .for and .f90 Fortran source files
    SFiles            []string   // .s source files
    SwigFiles         []string   // .swig files
    SwigCXXFiles      []string   // .swigcxx files
    SysoFiles         []string   // .syso object files to add to archive
    TestGoFiles       []string   // _test.go files in package
    XTestGoFiles      []string   // _test.go files outside package

    // Embedded files
    EmbedPatterns      []string // //go:embed patterns
    EmbedFiles         []string // files matched by EmbedPatterns
    TestEmbedPatterns  []string // //go:embed patterns in TestGoFiles
    TestEmbedFiles     []string // files matched by TestEmbedPatterns
    XTestEmbedPatterns []string // //go:embed patterns in XTestGoFiles
    XTestEmbedFiles    []string // files matched by XTestEmbedPatterns

    // Cgo directives
    CgoCFLAGS    []string // cgo: flags for C compiler
    CgoCPPFLAGS  []string // cgo: flags for C preprocessor
    CgoCXXFLAGS  []string // cgo: flags for C++ compiler
    CgoFFLAGS    []string // cgo: flags for Fortran compiler
    CgoLDFLAGS   []string // cgo: flags for linker
    CgoPkgConfig []string // cgo: pkg-config names

    // Dependency information
    Imports      []string          // import paths used by this package
    ImportMap    map[string]string // map from source import to ImportPath (identity entries omitted)
    Deps         []string          // all (recursively) imported dependencies
    TestImports  []string          // imports from TestGoFiles
    XTestImports []string          // imports from XTestGoFiles

    // Error information
    Incomplete bool            // this package or a dependency has an error
    Error      *PackageError   // error loading package
    DepsErrors []*PackageError // errors loading dependencies
}

type PackageError struct {
    ImportStack   []string // shortest path from package named on command line to this one
    Pos           string   // position of error (if present, file:line:col)
    Err           string   // the error itself
}

Se si itera sui moduli, verrà passato nella forma della seguente struct. Tutti i suoi campi possono anche essere utilizzati come parametri del template.

go
type Module struct {
    Path       string        // module path
    Query      string        // version query corresponding to this version
    Version    string        // module version
    Versions   []string      // available module versions
    Replace    *Module       // replaced by this module
    Time       *time.Time    // time version was created
    Update     *Module       // available update (with -u)
    Main       bool          // is this the main module?
    Indirect   bool          // module is only indirectly needed by main module
    Dir        string        // directory holding local copy of files, if any
    GoMod      string        // path to go.mod file describing module, if any
    GoVersion  string        // go version used in module
    Retracted  []string      // retraction information, if any (with -retracted or -u)
    Deprecated string        // deprecation message, if any (with -u)
    Error      *ModuleError  // error loading module
    Origin     any           // provenance of module
    Reuse      bool          // reuse of old module info is safe
}

type ModuleError struct {
    Err string // the error itself
}

Visualizza tutti i pacchetti

bash
$ go list -f "package {{.Dir}} {{.Name}}" ./...
package /golearn main
package /golearn/app cmd
package /golearn/cmd cmd
package /golearn/docs docs
package /golearn/tool tool
package /golearn/tool_test tool

Visualizza i moduli

bash
$ go list -m -f "mod {{.Path}} {{.Version}} {{.GoVersion}} {{.GoMod}}"
mod golearn  1.21.3 /golearn/go.mod

mod

go mod è un comando dedicato alla gestione dei moduli go.

sh
$ go mod help
Go mod provides access to operations on modules.

Note that support for modules is built into all the go commands,
not just 'go mod'. For example, day-to-day adding, removing, upgrading,
and downgrading of dependencies should be done using 'go get'.
See 'go help modules' for an overview of module functionality.

Usage:

        go mod <command> [arguments]

The commands are:

        download    download modules to local cache
        edit        edit go.mod from tools or scripts
        graph       print module requirement graph
        init        initialize new module in current directory
        tidy        add missing and remove unused modules
        vendor      make vendored copy of dependencies
        verify      verify dependencies have expected content
        why         explain why packages or modules are needed

Use "go help mod <command>" for more information about a command.

Ha i seguenti sottocomandi

  • download: scarica tutte le dipendenze indicate nel file go.mod nella cache locale
  • edit: modifica il file go.mod. L'interfaccia a riga di comando fornita è principalmente destinata ad essere utilizzata da altri strumenti o script.
  • init: inizializza un progetto gomod nella directory corrente
  • tidy: scarica le dipendenze mancanti ed elimina le dipendenze inutilizzate
  • graph: produce il grafico delle dipendenze
  • verify: verifica le dipendenze locali
  • why: spiega perché questi moduli sono dipendenti
  • vendor: esporta le dipendenze del progetto nella directory vendor

init

sh
$ go help mod init
usage: go mod init [module-path]

Il comando init viene utilizzato per inizializzare un progetto gomod. Il suo unico parametro è il percorso del modulo, che verrà utilizzato come base per scaricare le tue dipendenze in futuro. La sua regola di denominazione è generalmente

domain_name/user_name/repo_name

Ad esempio, poiché la maggior parte delle persone mette i propri progetti su github, potrebbe essere

github.com/jack/gotour

Non è consigliabile utilizzare simboli speciali come percorso del modulo. Ecco un caso d'uso

sh
$ mkdir gotour

$ cd gotour

$ go mod init "github.com/jack/gotour"
go: creating new go.mod: module github.com/jack/gotour

tidy

$ go help mod tidy
usage: go mod tidy [-e] [-v] [-x] [-go=version] [-compat=version]

Il comando tidy rimuoverà le dipendenze inutili in go.mod, ovvero le dipendenze non referenziate, e scaricherà le dipendenze referenziate ma non esistenti. Supporta i seguenti parametri

  • -v, produce le dipendenze del modulo eliminate
  • -e, ignora gli errori durante il processo e continua l'esecuzione
  • -x, produce il processo di esecuzione
  • -go=version, aggiorna la versione go nel file go.mod
  • -compact=version, mantiene eventuali checksum aggiuntivi necessari dalla versione Go principale specificata per caricare correttamente il grafico del modulo e causerà errori se tidy carica qualsiasi pacchetto importato da una versione del modulo diversa con la versione go di quella versione. Questo parametro è raramente utilizzato e generalmente causa errori solo durante i cambiamenti di versione. Puoi dare un'occhiata a questa risposta su stackoverflow go modules - go mod tidy error message: "but go 1.16 would select" - Stack Overflow

Ecco un esempio di utilizzo

sh
$ go mod tidy -v
unused github.com/246859/containers
unused github.com/246859/river
unused github.com/Jleagle/steam-go
unused github.com/Jleagle/unmarshal-go
unused github.com/KyleBanks/depth
unused github.com/Microsoft/go-winio
unused github.com/PuerkitoBio/purell
unused github.com/PuerkitoBio/urlesc
unused github.com/andeya/ameda
unused github.com/andeya/goutil
unused github.com/asaskevich/govalidator
unused github.com/buger/jsonparser
unused github.com/bwmarrin/snowflake
unused github.com/bytedance/go-tagexpr/v2
unused github.com/bytedance/sonic
unused github.com/cespare/xxhash/v2
unused github.com/chenzhuoyu/base64x
......

download

sh
$ go help mod download
usage: go mod download [-x] [-json] [-reuse=old.json] [modules]

Sebbene il nome del comando download significhi download, scarica solo le dipendenze nella cache delle dipendenze locale e non modifica il file go.mod. Il suo scopo è pre-scaricare le dipendenze nella cache dei file locale. Se desideri scaricare una determinata dipendenza, si consiglia di utilizzare go get o go mod tidy.

Ecco alcuni esempi di utilizzo

sh
$ go mod download -x gorm.io/gorm
# get https://goproxy.cn/gorm.io/gorm/@v/list
# get https://goproxy.cn/gorm.io/gorm/@v/list: 200 OK (0.084s)

Senza parametri, scaricherà tutte le dipendenze presenti nel file go.mod ma non nella cache delle dipendenze locale. Se non c'è nulla da scaricare, produrrà

go: no module dependencies to download

edit

sh
$ go help mod edit
usage: go mod edit [editing flags] [-fmt|-print|-json] [go.mod]

edit è un'interfaccia a riga di comando per modificare il file go.mod, solitamente utilizzata da altri programmi. Alcuni editor IDE utilizzano questi comandi per fornire supporto gomod. Supporta i seguenti parametri

  • -module, modifica il percorso del modulo
  • -go=version, modifica la versione go attesa
  • -require=path@version, aggiunge una dipendenza
  • -droprequire=path@version, rimuove una dipendenza
  • -exclude=path@version, aggiunge una dipendenza esclusa
  • -dropexclude=path@version, rimuove una dipendenza esclusa
  • -replace=old@version=new@version, aggiunge una dipendenza sostituita
  • -dropreplace=old@version, rimuove una dipendenza sostituita
  • -retract=version, aggiunge un elemento di rollback della versione
  • -dropretract=version, rimuove un elemento di rollback della versione

Ci sono anche altri parametri per la visualizzazione

  • -print, produce il contenuto del file
  • -json, produce in formato json

Ad esempio

$ go mod edit -print
module golearn

go 1.21.3

require (
        github.com/dstgo/task v1.2.0
        github.com/spf13/cast v1.5.1
        github.com/swaggo/swag v1.16.2
        golang.org/x/net v0.19.0
        gorm.io/gorm v1.25.5
)

graph

sh
$ go help mod graph
usage: go mod graph [-go=version] [-x]

Il comando graph produrrà il grafico delle dipendenze del progetto corrente. La sua leggibilità è scarsa e nella maggior parte dei casi non è destinato alla lettura umana. I risultati vengono solitamente elaborati e visualizzati in forma visiva. Ogni riga è una dipendenza, il formato è il seguente

Citante Citato

Ad esempio

golearn go@1.21.3

Supporta anche due parametri

  • -go=version, carica il grafico delle dipendenze utilizzando una determinata versione go. Il suo valore non può essere inferiore alla versione nel file go.mod.
  • -x, mostra i comandi eseguiti durante il processo.

Ecco un semplice esempio di utilizzo

sh
$ go mod graph
golearn github.com/246859/containers@v0.0.1
golearn github.com/246859/river@v0.1.0
golearn github.com/Jleagle/steam-go@v0.0.0-20230725082712-1053b441b1f2
golearn github.com/Jleagle/unmarshal-go@v0.0.0-20210227002040-694f544f9265
golearn github.com/KyleBanks/depth@v1.2.1
golearn github.com/Microsoft/go-winio@v0.6.1
golearn github.com/PuerkitoBio/purell@v1.1.1
golearn github.com/PuerkitoBio/urlesc@v0.0.0-20170810143723-de5bf2ad4578
golearn github.com/andeya/ameda@v1.5.3
golearn github.com/andeya/goutil@v1.0.1
golearn github.com/asaskevich/govalidator@v0.0.0-20230301143203-a9d515a09cc2
golearn github.com/buger/jsonparser@v1.1.1
golearn github.com/bwmarrin/snowflake@v0.3.0
golearn github.com/bytedance/go-tagexpr/v2@v2.9.11
......

vendor

sh
$ go help mod vendor
usage: go mod vendor [-e] [-v] [-o outdir]

vendor era una soluzione alternativa a gopath prima dell'introduzione di gomod. Ogni progetto go aveva una directory vendor, che memorizzava le dipendenze di ogni progetto separatamente nel formato domain/user/project, proprio come il gonfio node_module di nodeJs. Questo modo di gestire le dipendenze sembra davvero stupido ora, ma a quel tempo non c'era una soluzione migliore. Il motivo per cui vendor è mantenuto è perché go mantiene la promessa di compatibilità con le versioni precedenti. Alcuni vecchi progetti, incluso il codice sorgente go, potrebbero ancora utilizzare vendor.

Tornando al punto, vendor è un sottocomando di go mod che può esportare le dipendenze globali referenziate dal modulo corrente nella directory vendor.

sh
$ go mod vendor -h
usage: go mod vendor [-e] [-v] [-o outdir]
Run 'go help mod vendor' for details.

Ha i seguenti parametri

  • -o: specifica il percorso della cartella di output
  • -v: produce ogni dipendenza
  • -e: non esce quando si verifica un errore e continua

Ecco un esempio. Prima usa go list -m all per visualizzare le dipendenze referenziate dal progetto corrente

sh
$ go list -m all
github.com/dstgo/task
github.com/davecgh/go-spew v1.1.1
github.com/pkg/errors v0.9.1
github.com/pmezard/go-difflib v1.0.0
github.com/stretchr/objx v0.5.0
github.com/stretchr/testify v1.8.4
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405
gopkg.in/yaml.v3 v3.0.1

Esporta nella directory vendor corrente

sh
$ go mod vendor -v -e -o vendor
# github.com/davecgh/go-spew v1.1.1
## explicit
github.com/davecgh/go-spew/spew
# github.com/pkg/errors v0.9.1
## explicit
github.com/pkg/errors
# github.com/pmezard/go-difflib v1.0.0
## explicit
github.com/pmezard/go-difflib/difflib
# github.com/stretchr/testify v1.8.4
## explicit; go 1.20
github.com/stretchr/testify/assert
# gopkg.in/yaml.v3 v3.0.1
## explicit
gopkg.in/yaml.v3

La struttura della directory dopo l'esportazione è la seguente

└─vendor
    ├─github.com
    │  ├─davecgh
    │  │  └─go-spew
    │  │      └─spew
    │  ├─pkg
    │  │  └─errors
    │  ├─pmezard
    │  │  └─go-difflib
    │  │      └─difflib
    │  └─stretchr
    │      └─testify
    │          └─assert
    └─gopkg.in
    |    └─yaml.v3
    |
    |--modules.txt

Il file modules.txt è un file che descrive tutti gli elementi di dipendenza, simile all'attuale go.mod.

verify

sh
$ go help mod verify
usage: go mod verify

Questo comando verificherà se le dipendenze del progetto sono state modificate dopo essere state scaricate localmente. Ad esempio, se non ci sono problemi, produrrà all modules verified

sh
$ go mod verify
all modules verified

Altrimenti segnalerà dove sono avvenute le modifiche e terminerà il comando con uno stato anormale. Ad esempio

sh
$ go mod verify
gorm.io/gorm v1.25.5: dir has been modified (/go/mod/libs/gorm.io/gorm@v1.25.5)

why

$ go help mod why
usage: go mod why [-m] [-vendor] packages...

Spiega perché questo pacchetto è dipendente, in realtà produce il grafico delle dipendenze ad esso relativo. Ad esempio

sh
$ go mod why gorm.io/gorm
# gorm.io/gorm
golearn
gorm.io/gorm

Per impostazione predefinita, analizzerà solo l'importazione da main. Aggiungendo il parametro -m può analizzare la situazione di importazione di ogni pacchetto.

work

Il comando work è uno strumento di sviluppo locale per la gestione di più moduli go

bash
$ go work help
Work provides access to operations on workspaces.

Note that support for workspaces is built into many other commands, not
just 'go work'.

The commands are:

        edit        edit go.work from tools or scripts
        init        initialize workspace file
        sync        sync workspace build list to modules
        use         add modules to workspace file
        vendor      make vendored copy of dependencies

Use "go help work <command>" for more information about a command.

init

Il sottocomando init viene utilizzato per inizializzare un workspace. Questo comando creerà un file chiamato go.work

bash
$ go work init -h
usage: go work init [moddirs]
Run 'go help work init' for details.

Accetta il parametro [moddirs] per specificare quali moduli includere nella gestione. Ad esempio

bash
$ go work init ./service ./api

use

Il sottocomando use viene utilizzato per aggiungere directory di moduli gestiti a go.work

bash
$ go help work use
usage: go work use [-r] [moddirs]

Use provides a command-line interface for adding
directories, optionally recursively, to a go.work file.

Accetta [moddirs] come parametro e c'è anche -r che indica di cercare ricorsivamente i moduli nel percorso [moddirs]. Ad esempio

bash
$ go work use -r ./oss-api ./multi_modules

edit

La funzione del sottocomando edit è la stessa di go mod edit, entrambe lasciate all'interfaccia a riga di comando per essere utilizzate da altri strumenti e script.

$ go help work edit
usage: go work edit [editing flags] [go.work]

Edit provides a command-line interface for editing go.work,
for use primarily by tools or scripts. It only reads go.work;
it does not look up information about the modules involved.
If no file is specified, Edit looks for a go.work file in the current
directory and its parent directories

I parametri sono i seguenti

  • -fmt, formatta il file go.work

  • -use, -dropuse, aggiunge e rimuove percorsi di moduli

  • -replace=old[@v]=new[@v], -dropreplace=old[@v]=new[@v], utilizzati per aggiungere e rimuovere moduli da sostituire

  • -go, -toolchain=name, specifica la versione go e la toolchain da utilizzare

  • -print, stampa le modifiche finali senza riscrivere il file

  • -json, produce in formato json, non può essere utilizzato con -print. La struttura del tipo corrispondente è la seguente

    go
    type GoWork struct {
            Go        string
            Toolchain string
            Use       []Use
            Replace   []Replace
    }
    
    type Use struct {
            DiskPath   string
            ModulePath string
    }
    
    type Replace struct {
            Old Module
            New Module
    }
    
    type Module struct {
            Path    string
            Version string
    }

Alcuni esempi di utilizzo sono i seguenti, output formattato

bash
$ go work edit -fmt -print
go 1.22.0

use (
        ./ab/cd
        ./auth
        ./user
)

Output json

bash
$ go work edit -fmt -json
{
        "Go": "1.22.0",
        "Use": [
                {
                        "DiskPath": "./ab/cd"
                },
                {
                        "DiskPath": "./auth"
                },
                {
                        "DiskPath": "./user"
                }
        ],
        "Replace": null
}

sync

Il sottocomando sync viene utilizzato per ripristinare l'elenco dei moduli in go.work nei vari moduli nel workspace.

bash
$ go help work sync
usage: go work sync

Sync syncs the workspace's build list back to the
workspace's modules

Questo processo avviene principalmente dopo il completamento dello sviluppo locale, quando ogni modulo ha completato il lavoro di rilascio. A questo punto, utilizzando sync, aggiornerà le dipendenze in go.mod di tutti i moduli nel workspace in base alle relazioni di dipendenza di ciascun modulo, eliminando la necessità di aggiornarle manualmente.

vendor

Il comando vendor copierà tutte le librerie di dipendenze dei moduli nel workspace nella directory vendor.

bash
$ go work help vendor
usage: go work vendor [-e] [-v] [-o outdir]

La funzione è la stessa di go mod vendor, non mi dilungherò ulteriormente.

vet

Il comando vet è uno strumento di controllo statico degli errori per il codice sorgente del linguaggio go, proprio come gli strumenti lint di altri linguaggi, come Eslint.

sh
$ go vet -h
usage: go vet [build flags] [-vettool prog] [vet flags] [packages]
Run 'go help vet' for details.
Run 'go tool vet help' for a full list of flags and analyzers.
Run 'go tool vet -help' for an overview.

Ecco un esempio semplice. Supponiamo di avere il seguente codice sorgente

sh
$ cat main.go
package main

import "fmt"

func main(){
        fmt.Println("hello world!"
}

Esegui go vet senza parametri nella directory同级

sh
$ go vet
vet: ./main.go:6:28: missing ',' before newline in argument list (and 1 more errors)

vet segnalerà quale file e quale riga ha quale problema. Supporta flag di compilazione come parametri, come -n e -x, e supporta pacchetti, cartelle e nomi di file come parametri.

sh
$ go vet .
$ go vet main.go
$ go vet ./cmd
$ go vet runtime

Visualizza i parametri e le spiegazioni più dettagliati con il seguente comando.

sh
$ go tool vet help
vet is a tool for static analysis of Go programs.

vet examines Go source code and reports suspicious constructs,
such as Printf calls whose arguments do not align with the format
string. It uses heuristics that do not guarantee all reports are
genuine problems, but it can find errors not caught by the compilers.

Registered analyzers:

    asmdecl      report mismatches between assembly files and Go declarations
    assign       check for useless assignments
    atomic       check for common mistakes using the sync/atomic package
    bools        check for common mistakes involving boolean operators
    buildtag     check //go:build and // +build directives
    ......

Il comando go tool vet non può essere utilizzato direttamente per controllare il codice. Dovresti usare go vet. Il parametro [vet flag] di go vet supporta l'impostazione di analizzatori di codice. I valori disponibili sono i seguenti

asmdecl      Controlla se i file assembly corrispondono alle dichiarazioni go
assign       Controlla se ci sono variabili inutili
atomic       Controlla se l'atomicità viene violata quando si usa sync/atomic
bools        Controlla se gli operatori logici sono usati erroneamente
buildtag     Controlla i build tag
cgocall      Controlla comportamenti che violano le regole di passaggio dei puntatori cgo
composites   Controlla strutture composite non inizializzate, come map, chan
copylocks    Controlla se si verifica una copia del valore di un lock
directive    Controlla le istruzioni della toolchain go
errorsas     Controlla se viene passato un tipo non puntatore o non error a errors.As
framepointer Controlla se il codice assembly ottimizzato dalla compilazione cancella il frame pointer prima di salvarlo
httpresponse Controlla se httpresponse è usato erroneamente
ifaceassert  Controlla l'asserzione di tipo da interfaccia a interfaccia
loopclosure  Problemi di riferimento delle variabili di ciclo
lostcancel   context.WithCancel non usa la funzione cancel
nilfunc      Controlla se ci sono confronti inutili tra funzioni e nil
printf       Controlla se i parametri di formattazione di printf sono corretti
shift        Controlla se ci sono shift uguali o superiori alla larghezza dell'intero
sigchanyzer  Controlla chan os.Signal non bufferizzati
slog         Controlla chiamate di log strutturati non valide
stdmethods   Controlla se le firme dei metodi di interfacce note sono corrette
stringintconv Controlla la conversione di stringhe e interi
structtag    Controlla se i tag delle struct sono corretti
testinggoroutine Controlla se viene utilizzata la协程 per chiamare testing.Fatal nei test
tests        Controlla gli usi comuni errati di test ed esempi
timeformat   Controlla se il formato di (time.Time).Format o time.Parse è corretto
unmarshal    Passa tipi non puntatore o non interfaccia a unmarshal
unreachable  Controlla il codice non raggiungibile
unsafeptr    Controlla la conversione errata da uintptr a unsafe.Pointer
unusedresult Controlla i valori di ritorno di funzioni non utilizzati

Sono tutti analizzatori che analizzano un punto specifico. Ad esempio, l'analizzatore timeformat controlla se il formato di chiamata di time.Format è conforme alla sintassi corretta. Per impostazione predefinita, tutti gli analizzatori sopra menzionati sono abilitati. Per abilitarne uno singolarmente, è possibile utilizzare il seguente formato

sh
$ go vet -timeformat main.go

Per disabilitarne uno singolarmente

sh
$ go vet -timeformat=false main.go

Il codice sorgente di questi analizzatori si trova in cmd/vendor/golang.org/x/tools/go/analysis/passes. Ogni analizzatore è una trappola comune nel linguaggio go, quindi è altamente consigliato utilizzare il comando vet per controllare il tuo codice. Oltre a questi, supporta anche alcuni altri flag

  • -V, stampa solo la versione ed esce
  • -json, produce in formato json
  • -c=n, mostra il numero specificato di righe di conflitto nel contesto (sembra non avere alcun effetto)

Ci sono anche analizzatori esterni, come shadows, che è responsabile del rilevamento di problemi di nascondimento di variabili con nomi di variabili brevi. Poiché è esterno, deve essere scaricato con go install

sh
$ go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest

Il formato di utilizzo è il seguente

sh
$ go vet -vettool=$(which shadow)

test

sh
$ go test -h
usage: go test [build/test flags] [packages] [build/test flags & test binary flags]
Run 'go help test' and 'go help testflag' for details.

Il comando test è il comando fornito dalla toolchain del linguaggio go per le funzionalità di test. Questa funzione è molto importante. Per un software, test completi sono indispensabili. Qui viene introdotta solo brevemente come utilizzare il comando test. Per ulteriori informazioni sui test, visita: 测试

Oltre a supportare i parametri di compilazione del comando build, test supporta anche i seguenti parametri

  • -args, parametri di ingresso del programma
  • -c, compila il file binario di test del pacchetto corrente nella directory corrente ma non lo esegue, nominato come pkg.test
  • -exec, esegue alcuni altri comandi prima dell'inizio del test
  • -json, lo stile di output del test diventa json
  • -o, specifica il nome del percorso del file binario di test

Supporta anche molti testflag. Visualizza tutti i testflag con il comando help

sh
$ go help testflag
Il comando `go test` accetta sia flag che si applicano al `go test` stesso,
sia flag che si applicano al file binario di test generato.

Il comando `go test` riconosce i seguenti flag e li utilizza per controllare l'esecuzione di qualsiasi test:
        -bench regexp
        -benchtime t
        -count n
    ......

Ecco alcuni comunemente utilizzati

  • -v, produce i risultati di test di ogni caso di test.
  • -timeout duration, tempo di scadenza dell'esecuzione del test
  • -skip regexp, salta i casi di test specificati
  • -short, riduce il tempo di esecuzione per quei casi di test che richiedono molto tempo
  • -shuffle, mescola l'ordine di esecuzione di tutti i casi di test
  • -run regexp, esegui i casi di test specificati
  • -list regexp, elenca ogni caso di test
  • -cpu 1,2,4, specifica il numero di cpu
  • -count n, specifica quante volte eseguire ogni caso di test

L'uso più semplice è senza parametri. Esegue tutti i casi di test nel pacchetto corrente e produce i risultati.

sh
$ ls *_test.go
hello_test.go

$ go test
PASS
ok      golearn 0.522s

Specifica un file di test

sh
$ go test hello_test.go
ok      command-line-arguments  0.041s

Aggiungendo il parametro -v puoi visualizzare un output più dettagliato. È abbastanza comune.

sh
$ go test -v hello_test.go
=== RUN   TestHello
    hello_test.go:6: hello world!
--- PASS: TestHello (0.00s)
PASS
ok      command-line-arguments  0.041s

Specifica un caso di test

sh
$ go test -v -run TestHello
=== RUN   TestHello
    hello_test.go:6: hello world!
--- PASS: TestHello (0.00s)
PASS
ok      golearn 0.028s

Durante il test, il comando test ha due modalità. Prima parliamo della modalità cartella. Quando esegui il comando test senza il parametro package, eseguirà il test in modalità cartella. Ad esempio, i seguenti comandi

sh
$ go test
$ go test -v

In questa modalità, la cache di test è disabilitata. L'altra modalità è la modalità elenco. Quando il parametro package non è vuoto, eseguirà il test in modalità elenco. La differenza con la prima è se la cache di test è abilitata. Ad esempio, i seguenti

sh
$ go test -v .
$ go test -v ./...
$ go test .
$ go test -v net/http

In modalità elenco, go compilerà ed eseguirà i file di test di ogni pacchetto nel pacchetto specificato in file binari. Per evitare di eseguire ripetutamente i test, go memorizzerà i risultati nella cache per impostazione predefinita e non ricompilerà durante la seconda esecuzione. La cache verrà abilitata per impostazione predefinita quando si utilizzano i seguenti parametri

  • -benchtime
  • -cpu
  • -list
  • -parallel
  • -run
  • short
  • -timeout
  • -failfast
  • -v

Utilizzando parametri diversi da questi è possibile disabilitare la cache. Il metodo consigliato ufficialmente è utilizzare -count=1 per disabilitare la cache. Ad esempio

sh
$ go test -v -count=1 ./...

Direttive

A differenza dei comandi, le direttive go esistono nel codice sorgente in forma di codice hardcoded. Hanno un altro nome più tecnico: direttive di compilazione (pragma directives).

I compilatori e i linker cambieranno il loro comportamento a causa di esse, raggiungendo così l'effetto di controllare la compilazione, simile alle macro nel linguaggio C. Naturalmente, non tutte le direttive sono utilizzate per influenzare la compilazione. Alcune sono utilizzate per altri comportamenti funzionali. Ad esempio, la direttiva generate è solitamente utilizzata per funzionalità di generazione di codice. Queste direttive esistono solitamente sotto forma di commenti e iniziano con il prefisso //go:, senza alcuno spazio nel mezzo, come la direttiva //go:generate. Tutti i tipi di direttive sono divisi in due categorie

  • Direttive funzionali, queste sono direttive funzionali fornite da go che possono essere utilizzate liberamente, come generate, embed, build.
  • Direttive del compilatore, queste direttive devono essere utilizzate con cautela. Un uso improprio può portare a risultati imprevedibili.

Ad eccezione delle direttive funzionali, la maggior parte delle direttive può agire solo sulle firme delle funzioni. Per le direttive del compilatore, è possibile eseguire il comando go doc compile per visualizzare le sue direttive. Per tutte le direttive, è possibile trovare informazioni su di esse in cmd/compile/internal/ir/node.go: 440.

generate

sh
$ go help generate
usage: go generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]

La direttiva generate, come suggerisce il nome, è relativa alla generazione. Solitamente il suo scopo è eseguire comandi che generano codice e aggiornano il codice sorgente, ma in realtà può eseguire qualsiasi comando. Inoltre, a differenza di altre direttive, generate ha un comando dedicato per eseguire tutte le direttive generate presenti nei file sorgente. Può accettare nomi di file o nomi di pacchetti come parametri di input per indicare quali file eseguire le direttive generate. Ecco i suoi altri parametri.

  • -run=regex, esegue la direttiva generate specificata
  • -skip=regex, salta la direttiva generate specificata
  • -n, stampa i comandi che verranno eseguiti
  • -x, stampa i comandi eseguiti durante il processo
  • -v, produce i file elaborati

Inoltre, i comandi eseguiti nella direttiva generate supportano anche i seguenti parametri incorporati

  • $GOARCH, architettura cpu
  • $GOOS, sistema operativo
  • $GOFILE, nome file
  • $GOLINE, numero di riga
  • $GOPACKAGE, nome pacchetto
  • $GOROOT, go root
  • $DOLLAR, simbolo del dollaro
  • $PATH, variabile d'ambiente path

Ecco un esempio. Non c'è codice, solo un commento

go
package main

//go:generate echo "hello world!"

Esegui il comando

$ go generate .
hello world!

Questo esempio esegue il comando go

go
package main

//go:generate go version

Esegui il comando

sh
$ go generate .
go version go1.21.3 windows/amd64

La direttiva generate può essere utilizzata per eseguire qualsiasi comando, come swagger per generare documentazione API o Wire per generare codice IOC. Tuttavia, questa direttiva non è adatta per eseguire comandi particolarmente complessi. È adatta per eseguire comandi brevi. Se ci sono requisiti complessi, è possibile utilizzare script o makefile come sostituti.

embed

La direttiva embed è stata aggiunta nella versione 1.16. Il suo scopo è includere file statici nel file binario, come modelli HTML. Il suo formato è il seguente

go
//go:embed pattern

pattern può essere un'espressione glob, una cartella o un file specifico. Ecco un esempio

go
package main

import "embed"

//go:embed *
var static embed.FS

La direttiva embed richiede di essere posizionata sopra una variabile globale di tipo embed.Fs. Nota che deve essere una variabile globale e per utilizzarla è necessario importare il pacchetto embed. In questo esempio, * rappresenta che tutti i file nella cartella corrente verranno inclusi nel file binario, ma non consentirà cartelle che iniziano con ..

L'esempio seguente mostra come leggere il contenuto da un file incorporato

go
package main

import (
  "embed"
  "fmt"
)

//go:embed *.txt
var static embed.FS

func main() {
  bytes, err := static.ReadFile("hello.txt")
  if err != nil {
    panic(err)
  }
  fmt.Println(string(bytes))
}

Ha solo tre metodi e l'utilizzo non è diverso da un normale file system. Poiché implementa l'interfaccia io/Fs, può anche essere passato come oggetto Fs.

go
func (f FS) Open(name string) (fs.File, error)
func (f FS) ReadFile(name string) ([]byte, error)
func (f FS) ReadDir(name string) ([]fs.DirEntry, error)

L'esempio seguente mostra come incorporare un file html tramite la direttiva embed e accedervi tramite un servizio http.

go
package main

import (
  "embed"
  "net/http"
)

//go:embed index.html
var htmlFs embed.FS

func main() {
  http.Handle("/", http.FileServer(http.FS(htmlFs)))
  http.ListenAndServe(":8080", http.DefaultServeMux)
}

Il risultato dell'accesso è il seguente

sh
$ curl -s -GET 127.0.0.1:8080
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>hello world!</title>
</head>
<body>
<H1>Hello World!</H1>
<script>
    alert("hello world!");
</script>
</body>
</html>

La direttiva embed supporta anche che il tipo di variabile globale possa essere []byte. Ecco un esempio

go
package main

import (
  _ "embed"
  "net/http"
)

//go:embed index.html
var rawdata []byte

func main() {
  http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
    writer.Write(rawdata)
  })
  http.ListenAndServe(":8080", http.DefaultServeMux)
}

L'effetto realizzato è simile all'esempio precedente.

sh
$ curl -s -GET 127.0.0.1:8080
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>hello world!</title>
</head>
<body>
<H1>Hello World!</H1>
<script>
    alert("hello world!");
</script>
</body>
</html>

build

Nella sezione build-Controllo della compilazione, è stato discusso come utilizzare la direttiva // +build per controllare il comportamento di compilazione. La direttiva //go:build è stata introdotta nella versione 1.17 con l'intenzione di sostituire la direttiva precedente, ma ora siamo alla versione 1.21 e non è ancora stata sostituita. Si stima che in futuro esisteranno in modo coesistente. La documentazione ufficiale ha anche una introduzione su questa nuova direttiva: build constraints. La sua funzione non è molto diversa dalla precedente, ma la sintassi è più rigorosa e supporta le espressioni booleane. Ecco un esempio

go
//go:build (linux && 386) || (darwin && !cgo)

package pkg_name

Questo modo è molto più leggibile rispetto al precedente.

line

La direttiva line influenzerà il numero di riga, il numero di colonna e il nome del file della riga successiva. Il suo scopo si limita a questo e nella maggior parte dei casi potrebbe essere utilizzato per il debug di errori. Ad esempio, quando si verifica un errore, cambierà le informazioni prodotte dal compilatore.

go
package main

var a undefinedType

func main() {

}

Normalmente, il compilatore produrrà

.\main.go:3:7: undefined: undefinedType

Ma se si utilizza la direttiva line, è diverso

go
package main

//line abc.go:10:100
var a undefinedType

func main() {

}

Allora il suo output sarà

abc.go:10:106: undefined: undefinedType

E a causa di ragioni storiche, la direttiva line è anche l'unica direttiva con un utilizzo diverso dalle altre direttive. Il suo formato è

go
//line filename:line:column

Come puoi vedere, non richiede il prefisso go:.

linkname

Questa operazione di direttiva può essere utilizzata per collegare funzioni o variabili globali di altri pacchetti, anche se sono di tipo privato. Questa operazione appare frequentemente nella libreria standard, specialmente in runtime. Alcune funzioni senza corpo di funzione sono implementate in questo modo, mentre altre funzioni con corpo di funzione vuoto sono implementate in assembly. Ecco il suo utilizzo. Il formato di utilizzo è il seguente

go
//go:linkname nome_tipo_collegato tipo_collegato

E prima di utilizzarla, ad esempio, importa il pacchetto unsafe. Ecco un esempio semplice di collegamento di un tipo privato nella libreria standard

go
import (
  "fmt"
  "unsafe"
)

//go:linkname memhash runtime.memhash
func memhash(p unsafe.Pointer, h, s uintptr) uintptr

func MemHash(data []byte) uint64 {
  ptr := unsafe.Pointer(unsafe.SliceData(data))
  return uint64(memhash(ptr, 0, uintptr(len(data))))
}

func main() {
  fmt.Println(MemHash([]byte("hello")))
}

Output

15395306441938000233

Collega la funzione privata runtime.memhash alla funzione che abbiamo dichiarato noi. Questa funzione non ha un corpo di funzione, solo una firma, e funge solo da supporto. La funzione memhash calcola il valore hash in base alla memoria dato un puntatore, un seed hash e un offset di memoria. Questo processo di collegamento viene completato durante la compilazione.

Se non è della libreria standard, la situazione è leggermente diversa. Ad esempio, c'è una funzione test nel pacchetto example. Prima del collegamento, è necessario importare anonimamente questo pacchetto.

go
package example

// Un tipo privato, inaccessibile dall'esterno.
func test() string {
  return "a"
}
go
package main

import (
  "fmt"
  _ "golearn/example"
  _ "unsafe"
)

//go:linkname test golearn/example.test
func test() string

func main() {
  fmt.Println(test())
}

Output

a

Come puoi vedere, il collegamento è riuscito. Questo metodo può aggirare il sistema di moduli di go e fare ciò che si vuole, ma non è consigliabile utilizzarlo su larga scala, a meno che tu non sappia cosa stai facendo.

noinline

La direttiva noinline indica che una funzione non deve essere ottimizzata con l'inlining, anche se è molto semplice. Ecco un esempio semplice

go
package main

func val() string {
  return "val"
}

func main() {
  var c = val()
  _ = c
}

val è una funzione molto semplice che restituisce un letterale di stringa. Poiché è troppo semplice e il risultato è sempre prevedibile, durante la compilazione verrà ottimizzata dal compilatore nella seguente forma

go
package main

func main() {
  var c = "val"
  _ = c
}

Ecco come appare in assembly. Come puoi vedere, non c'è chiamata alla funzione val.

TEXT    main.val(SB), NOSPLIT|NOFRAME|ABIInternal, $0-0
FUNCDATA        $0, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
FUNCDATA        $1, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
LEAQ    go:string."val"(SB), AX
MOVL    $3, BX

FUNCDATA        $0, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
RET

Ora aggiungiamo la direttiva noinline

go
package main

//go:noinline
func val() string {
  return "val"
}

func main() {
  var c = val()
  _ = c
}

Ed ecco la sua forma assembly

CMPQ    SP, 16(R14)
PCDATA  $0, $-2
JLS     17
PCDATA  $0, $-1
PUSHQ   BP
MOVQ    SP, BP
FUNCDATA        $0, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
FUNCDATA        $1, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
PCDATA  $1, $0
CALL    main.val(SB)
POPQ    BP
RET

Questa volta puoi vedere molto chiaramente la chiamata main.val, ed è esattamente la funzione della direttiva noinline: impedire l'inlining delle funzioni durante l'ottimizzazione del compilatore.

nosplit

La direttiva nosplit serve a saltare il rilevamento di overflow dello stack. Poiché il modello di schedulazione concorrente di go è di tipo preemptive, se una funzione esegue codice di livello molto basso e altre goroutine non dovrebbero essere preemptive quando chiamano questa funzione, è possibile utilizzare questa direttiva per indicarlo.

go
//go:nosplit
func nosplitFn()

Dopo aver utilizzato questa direttiva, non ci sarà più crescita dello stack.

noescape

noescape, come si può facilmente intuire dal nome, è relativo all'escape. Il suo scopo è indicare che la funzione corrente non comporterà comportamenti di escape della memoria. Dopo l'esecuzione, tutte le risorse vengono recuperate e questa funzione deve avere solo una firma senza corpo di funzione. In questo caso, generalmente l'implementazione della funzione è realizzata in assembly.

Ad esempio, memhash utilizzato in precedenza utilizzerà questa direttiva

go
//go:noescape
//go:linkname memhash runtime.memhash
func memhash(p unsafe.Pointer, h, s uintptr) uintptr

In questo modo, il compilatore non eseguirà l'analisi di escape su di essa. La premessa è che devi garantire che non si verifichi escape. Se si verifica, non si sa quali saranno le conseguenze.

uintptrescapes

La direttiva uintptrescapes indica che i parametri di tipo uintptr in questa funzione sono stati convertiti in valori puntatore e sono fuggiti sull'heap e devono essere mantenuti in vita. Questa direttiva è generalmente utilizzata per alcune chiamate di sistema di basso livello. Nella maggior parte dei casi, non è necessario conoscerla.

go
//go:uintptrescapes
func nosplit(ptr uintptr) uintptr

In passato dovrebbe esserci stata una direttiva notinheaps utilizzata per indicare che un tipo non può allocare memoria sull'heap, ma non si sa in quale versione è stata rimossa.

norace

La direttiva norace indica che l'accesso alla memoria di una funzione non richiede più analisi delle race condition. Generalmente viene utilizzata quando si esegue codice di basso livello non adatto per l'analisi delle race condition.

go
//go:norace
func low_level_code(ptr uintptr) uintptr

TIP

Alcune direttive sono limitate all'uso solo dal pacchetto runtime e non possono essere utilizzate dall'esterno. Coinvolgeranno cose più profonde. Se vuoi saperne di più, puoi vedere le informazioni su di esse in Runtime-only compiler directives.

Golang by www.golangdev.cn edit