Skip to content

Linha de Comando

Os comandos em Go incluem um conjunto completo de ferramentas que abrangem documentação, formatação, verificação de código, compilação, testes, gerenciamento de dependências e muito mais, cobrindo todos os aspectos do desenvolvimento Go.

text
bug         Reportar vulnerabilidades
build       Compilar pacotes e dependências
clean       Limpar arquivos objeto
doc         Exibir documentação do código-fonte
env         Exibir informações de variáveis de ambiente Go
fix         Corrigir problemas de compatibilidade de API devido a mudanças de versão do Go
fmt         Formatar código-fonte
generate    Geração de código
get         Adicionar dependências
install     Instalar e compilar pacotes
list        Comando de listagem de pacotes/módulos
mod         Comando de manutenção de módulos
work        Comando de manutenção de área de trabalho
run         Compilar e executar
test        Testar
tool        Executar ferramentas Go especificadas
version     Exibir informações de versão do Go
vet         Verificar e reportar possíveis problemas no código-fonte

Este artigo apenas descreve e introduz brevemente seu uso. Todo o conteúdo é referenciado da documentação oficial. Para saber mais detalhes, visite cmd/go.

help

O primeiro comando a conhecer é help, que permite ler o uso dos comandos. Existem dois usos: para obter informações breves de uso, você pode adicionar a flag -h após o comando especificado, por exemplo

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

Go exibirá concisamente o uso do comando e também indica que, para obter informações mais detalhadas, você precisa usar o comando help

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'.

Use bem o comando help para obter muitas informações sobre comandos.

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

O comando doc exibirá comentários de documentação para pacotes especificados, constantes, funções, tipos, variáveis, métodos e até campos de struct. Sem nenhum parâmetro, ele exibirá os comentários do pacote atual

sh
$ go doc

Você também pode especificar um pacote para visualizar, por exemplo, visualizar a documentação do pacote 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.
......

Ou um tipo específico

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

Ou uma função específica

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.

Possui as seguintes flags comuns

  • -u: Visualizar tipos privados
  • -all: Visualizar toda a documentação de um pacote especificado
  • -short: Apenas uma descrição breve em uma linha
  • -src: Exibir código-fonte
  • -cmd: Para pacotes que pertencem a comandos go, também exibir documentação de código dentro deles.

Por exemplo, visualizar a variável runtime.inf, que é uma variável não exportada

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

var inf = float64frombits(0x7FF0000000000000)

Usar bem o comando doc pode ajudá-lo a ler documentação de forma mais conveniente.

Outra maneira de ler documentação de comandos é ler o código-fonte, pois a documentação de alguns comandos não é escrita de forma tão detalhada, enquanto o código-fonte tem explicações mais detalhadas. Como esses comandos são todos escritos em Go, a leitura é bastante conveniente. Esses comandos estão localizados no pacote src/cmd, onde cada subpacote é um comando separado, e a entrada está no arquivo 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,
    }
}

Aqui você encontrará todos os subcomandos do Go e suas informações de documentação de ajuda.

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.

Este comando não possui parâmetros ou flags. Ele abrirá a página de issues do repositório github.com/golang/go no seu navegador padrão para facilitar o feedback de bugs, não tendo nenhuma outra função.

version

O comando version permite visualizar informações de versão do Go.

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

Quando executado sem parâmetros, ele exibirá a versão atual da linguagem Go

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

Ele também aceita caminhos de arquivo como parâmetros e exibirá a versão do Go usada para compilar todos os arquivos binários identificáveis nesse caminho.

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

O parâmetro -v especifica que o comando version tente exibir a versão do Go de arquivos não identificáveis, e o parâmetro -m exibirá informações de módulo e alguns parâmetros de compilação do arquivo binário. Aqui está um exemplo simples.

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

O próprio go é um arquivo binário. Na verdade, quando executado sem parâmetros, go version exibe a versão da linguagem Go do seu próprio arquivo binário, pois toda a cadeia de ferramentas cmd/go é implementada pela própria linguagem Go.

env

O comando env permite visualizar todas as variáveis de ambiente do Go. Modificar essas variáveis de ambiente afetará o comportamento da cadeia de ferramentas Go.

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

Executar este comando sem parâmetros exibirá os valores de todas as variáveis de ambiente do Go

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

Usar o nome de uma variável de ambiente como parâmetro exibirá apenas o valor dessa variável

sh
$ go env GO111MODULE
on

Adicionar -json exibirá no formato JSON

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

Usar a flag -w com parâmetro no formato var=value modificará permanentemente o valor de uma variável

sh
$ go env -w GO111MODULE=on

Usar a flag -u pode restaurar uma variável para seu valor padrão

sh
$ go env -u GO111MODULE

Executar go help environment permite visualizar a descrição de cada variável de 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.
    ......

A seguir, apresentamos algumas variáveis de ambiente comumente usadas

GOVERSION

O valor desta variável de ambiente depende da versão da linguagem Go, e o número da versão vem do arquivo $GOROOT/VERSION, que registra a versão atual do Go e o tempo de compilação.

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

O valor da variável runtime.Version é o mesmo que GOVERSION, e esta variável de ambiente não pode ser modificada.

GOENV

O diretório $GOROOT terá um arquivo de configuração padrão chamado 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

Seu formato é simplesmente key=value. Os valores das variáveis de ambiente modificados pelo comando go env -w key=value serão gravados no arquivo de configuração. No entanto, você pode não usar o arquivo de configuração padrão. A variável de ambiente GOENV pode especificar manualmente o endereço do arquivo de configuração env, e o valor da variável de ambiente GOENV só pode ser substituído pela variável de ambiente do sistema operacional e não pode ser modificado pelo comando go env -w.

GOHOSTARCH

Representa a arquitetura da CPU da máquina local, apenas para exibição. O valor desta variável de ambiente não é lido do arquivo de configuração e não pode ser modificado.

GOHOSTOS

Representa o sistema operacional da máquina local, apenas para exibição. O valor desta variável de ambiente não é lido do arquivo de configuração e não pode ser modificado.

GOOS

Durante a compilação, o valor de GOOS determinará em qual sistema de destino o código-fonte será compilado. O valor padrão é GOHOSTOS, que é o sistema operacional da máquina local. Possui as seguintes opções

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

Os sistemas operacionais suportados não se limitam a estes. Use o comando go tool dist list para visualizar todos os valores suportados

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 a compilação, o valor de GOARCH determinará qual arquitetura de CPU será usada para compilação. O valor padrão é GOHOSTARCH, que é a arquitetura da CPU da máquina local. Possui as seguintes opções

  • amd64
  • 386
  • arm
  • ppc64

As arquiteturas suportadas não se limitam a estas. Use o comando go tool dist list para visualizar todos os valores suportados

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

É importante notar que GOOS e GOARCH não podem ser combinados arbitrariamente. Alguns sistemas operacionais suportam apenas arquiteturas de CPU específicas.

GOROOT

GOROOT representa o diretório raiz da instalação da linguagem Go. O valor de GOROOT não pode ser modificado diretamente e só pode ser substituído pela variável de ambiente do sistema operacional.

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

No diretório raiz, existem várias pastas ou arquivos importantes

  • lib: Armazena algumas dependências. Atualmente, há apenas uma biblioteca que contém informações de fuso horário de vários países, localizada em $GOROOT/lib/time. Os arquivos binários compilados não incluirão essas informações de fuso horário.

  • pkg: Armazena algumas bibliotecas de ferramentas e arquivos de cabeçalho. Por exemplo, o comando go tool procurará os arquivos binários da cadeia de ferramentas Go no diretório $GOROOT/pkg/tool

  • bin: Armazena arquivos binários. Por padrão, há apenas dois arquivos executáveis: go e gofmt. $GOROOT/bin deve ser adicionado às variáveis do sistema, caso contrário, os comandos go não poderão ser usados.

  • src: Armazena o código-fonte Go

  • VERSION: Este arquivo armazena as informações de versão da linguagem Go

  • go.env: Este arquivo é o arquivo de configuração env padrão

GOPATH

O valor padrão de GOPATH é $HOME/go. O valor desta variável de ambiente especifica onde procurar arquivos importados ao analisar instruções import. Nos primeiros dias, antes do gomod, GOPATH era usado especificamente para armazenar várias bibliotecas de terceiros. Sua estrutura é a seguinte

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)

Após o surgimento do gomod, GOPATH tornou-se apenas um local para armazenar dependências baixadas pelo go get e arquivos binários baixados e compilados pelo go install. É importante notar que a localização de GOPATH não pode ser a mesma que GOROOT, caso contrário não funcionará.

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

Até o momento em que escrevo este artigo, a versão da linguagem Go chegou à go1.21.3. Exceto por projetos muito antigos, basicamente ninguém usa mais gopath para gerenciar dependências.

GOBIN

GOBIN é usado para armazenar arquivos binários executáveis de terceiros baixados e compilados pelo go install. Seu valor padrão é $GOPATH/bin. Assim como $GOROOT/bin, este diretório deve ser adicionado às variáveis de ambiente do sistema operacional, caso contrário, os arquivos binários neste diretório não poderão ser usados.

GOMODCACHE

GOMODCACHE indica onde as dependências baixadas pelo go get são armazenadas. O valor padrão é $GOPATH/pkg/mod. O formato de armazenamento é o seguinte

$GOMODCACHE/domain/username/project@version

No mesmo nível, haverá uma pasta chamada sumdb para armazenar informações relacionadas ao banco de dados de soma de verificação de dependências.

GOCACHE

Armazena informações de cache usadas para compilação. O valor padrão é $HOME/.cache/go-build. Um arquivo README será gerado neste diretório.

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.

Cada build gerará muitos arquivos, e o Go armazenará esses arquivos em cache para reutilização na próxima compilação.

GOTEMPDIR

Usado para arquivos temporários gerados durante a compilação, como o arquivo binário temporário a ser executado pelo go run. Seu valor padrão é o diretório temporário especificado pelo sistema operacional: /tmp no Mac ou Linux, %TEMP% no Windows. Também pode ser modificado para uma localização especificada pelo usuário.

GO111MODULE

Esta variável de ambiente indica qual método usar para gerenciar dependências de projetos Go. Possui três valores disponíveis

  • off: Desativa o gomod, usa gopath e ignora todos os arquivos go.mod
  • on: Usa gomod, não usa gopath (padrão).
  • auto: Detecção automática. Se o arquivo do projeto contiver go.mod, usará gomod para gerenciamento

TIP

Por que se chama GO111MODULE e não simplesmente GOMODULE? Porque o gomod foi introduzido pela primeira vez na versão go1.11.

GOPROXY

Proxy de módulo Go. O valor padrão é https://proxy.golang.org,direct. As URLs são separadas por vírgula. direct significa usar diretamente o VCS para pular o proxy de módulo. O segundo só será executado se o primeiro não estiver acessível. Outra opção disponível é off, que proíbe o download de qualquer módulo. Além disso, GOPROXY também pode ser um endereço de arquivo, como

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

Usar go get -x permite visualizar os comandos executados durante o processo de download de dependências, para saber se está usando 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

Usar proxy de módulo pode efetivamente melhorar a velocidade de download de módulos. Para usuários na China, basicamente não é possível acessar o proxy oficial padrão sem usar proxy. Atualmente, proxies de módulo de terceiros públicos e confiáveis incluem

  • https://proxy.golang.com.cn: Open source e também fornece serviços empresariais
  • https://goproxy.cn: Fornecido e open source pela Qiniu Cloud

Claro, também há soluções open source para construir seu próprio proxy de módulo: goproxy

GOSUMDB

GOSUMDB é usado para definir o endereço do banco de dados de detecção de soma de verificação de bibliotecas de dependências. O padrão é sum.golang.org. Quando você define um proxy, o Go acessará o banco de dados de verificação através do proxy.

GOPRIVATE

A variável de ambiente GOPRIVATE é usada para definir bibliotecas privadas. As bibliotecas correspondentes não serão verificadas através do sumdb e não usarão proxy, sendo baixadas diretamente através do VCS. Suporta configurações de curinga, usando vírgulas como separador. Como mostrado abaixo, todas as dependências com sufixo corp.example.com e nomeadas github.com/gohper/myproject não usarão proxy ou sumdb.

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

Também é possível definir diretamente um usuário ou organização específico

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

GONOPROXY

Indica quais dependências não precisam usar proxy. As regras são as mesmas de GOPRIVATE e substituirão GOPRIVATE.

GONOSUMDB

Indica quais dependências não precisam passar pelo banco de dados de soma de verificação. As regras são as mesmas de GOPRIVATE e substituirão GOPRIVATE.

GOINSECURE

Indica quais dependências devem ser baixadas diretamente usando VCS. As regras são as mesmas de GOPRIVATE e serão substituídas por GONOPROXY e GONOSUMDB.

GOVCS

Define o sistema de controle de versão para gerenciamento de módulos. O padrão é public:git|hg,private:all. Também é possível restringir VCS para domínios específicos, por exemplo

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

Na restrição acima, github só pode usar git, evil.com não é permitido, e | pode representar múltiplos VCS. Se não houver restrições, pode ser definido da seguinte forma

GOVCS=*:all

Se não for permitido o uso de nenhum VCS, pode ser definido da seguinte forma

GOVCS=*:off

GOWORK

Define se a área de trabalho está habilitada. O padrão é vazio, ou seja, habilitado. Se definido como off, será desabilitado e ignorará todos os arquivos go.work.

GOTOOLDIR

Define a localização da cadeia de ferramentas Go a ser usada. O padrão é $GOROOT/pkg/tool, onde a cadeia de ferramentas padrão também está localizada.

GODEBUG

Define opções de depuração, controlando parcialmente o comportamento de execução de programas Go na forma de pares chave-valor, por exemplo

GODEBUG=http2client=0,http2server=0

Essas configurações são para facilitar o retorno a comportamentos antigos do Go quando surgem mudanças incompatíveis durante atualizações de versão. Por exemplo, em 1.21, panic(nil) não é mais permitido. Para isso, a equipe oficial do Go registrou especificamente o GODEBUG History. Visite GODEBUG para saber mais detalhes.

CGO_ENABLED

Indica se o cgo está habilitado. O padrão é 1, ou seja, habilitado. Definir como 0 desabilita.

As variáveis de ambiente acima são as mais comumente usadas. Para algumas menos comuns, como CGO, WASM, etc., interessados podem aprender por conta própria.

build

O Go suporta dois tipos de compiladores: gccgo e gc. gcc é um antigo compilador c/c++ que suporta várias linguagens, incluindo Go. O último, gc, não significa garbage collector, mas sim Go Compiler. A linguagem Go completou sua auto-inicialização na versão go1.5. gc é um compilador escrito completamente em Go, e seu código-fonte está localizado no pacote cmd/compile. Como é totalmente implementado em Go, é muito conveniente para entender e aprender seu mecanismo interno. Por padrão, o compilador usa gc para compilação. A propósito, o depurador da linguagem Go também vem em dois tipos: gdb e dlv. O primeiro é um antigo depurador c/c++ que suporta várias linguagens, incluindo Go. O último é um depurador escrito em Go que oferece suporte mais amigável à linguagem Go. Também é open source e recomendado.

O comando build compila arquivos de código-fonte Go em arquivos binários executáveis. Você experimentará uma experiência de compilação bastante rápida, que é uma das características da linguagem Go.

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

Ele recebe três parâmetros: um é o caminho de saída do arquivo indicado pela flag -o, outro são as flags de compilação build flags usadas para definir o comportamento de compilação, e o último é o pacote a ser compilado. Este parâmetro deve ser colocado por último. Aqui está um exemplo simples sem usar flags de compilação.

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

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

./bin/golearn.exe representa o caminho de saída, e golearn representa o módulo a ser compilado. Também pode ser um arquivo de entrada ou um diretório. Por exemplo, o exemplo simples abaixo usa o arquivo de entrada main.go como alvo de compilação.

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

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

Durante a compilação, ele ignorará todos os arquivos que terminam com _test.go, pois por convenção são arquivos de teste.

Além disso, o comando build suporta muitas flags de compilação para controlar comportamentos durante a compilação.

  • -x: Exibe instruções detalhadas durante o processo de compilação
  • -n: Similar a -x, mas apenas exibe essas instruções sem executá-las.
  • -v: Exibe os pacotes compilados
  • -p: Número de processos simultâneos durante a compilação
  • -a: Força a reconstrução, mesmo que já esteja atualizado.
  • -compiler: Especifica qual compilador usar, gccgo ou gc, sendo o último escrito em Go.
  • -race: Habilita detecção de corrida
  • -msan: Habilita análise de memória
  • -asan: Habilita análise de endereço
  • -cover: Habilita detecção de cobertura de código
  • -buildmode: Especifica o modo de compilação, com opções archive, c-archive, c-shared, default, shared, exe, pie, plugin.
  • -pgo: Especifica arquivo pgo
  • -trimpath: Remove prefixos de caminho de arquivos de código-fonte. Por exemplo, o caminho relativo /var/lib/go/src/main.go após a remoção terá apenas o caminho relativo ao caminho do módulo /main.go quando obtido através de runtime em tempo de execução. Habilitar esta opção aumentará significativamente o tempo de compilação, em cerca de 20-40%, dependendo do número de arquivos.
  • -toolexec: Alguns comandos Go executados antes da compilação, no formato -toolexec 'cmd args'.
  • -gcflags: Especifica algumas tags do compilador gc
  • -gccgoflags: Especifica algumas tags do compilador gccgo
  • -ldflags: Especifica algumas tags da ferramenta de link

Para parâmetros de transmissão como ldflags, você pode passar parâmetros como "-help" para obter seus valores possíveis, por exemplo

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

Os acima são os mais comumente usados. Para outros menos comuns, você pode aprender por conta própria.

gcflags

Através de gcflags, você pode passar alguns parâmetros para o compilador gc para controlar comportamentos específicos. Seu formato de uso é -gcflags="pattern=args list", onde args list é a lista de parâmetros e pattern é o escopo de aplicação, com os seguintes valores disponíveis

  • main: Caminho do pacote de nível superior onde está o arquivo de entrada
  • all: Módulo atual e todas as suas dependências no modo atual
  • std: Biblioteca padrão
  • cmd: Aplica-se a todos os arquivos de código-fonte no pacote cmd
  • Curingas, como ., ./..., cmd/....

Esta regra de pattern se aplica a todas as flags que suportam este formato, como ldflags. Use o seguinte comando para visualizar os valores disponíveis de seus parâmetros

sh
$ go build -gcflags -help
usage: compile [options] file.go...
  -%    debug non-static initializers
  -+    compile runtime
  -B    disable bounds checking
  -C    disable printing of column numbers 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 error locations affected by //line directives
  -N    disable optimizations
  -S    print assembly listing
  -V    print version and exit
  -W    debug parse tree after type checking
  ......

A seguir, apresentamos alguns parâmetros comumente usados

  • -S: Exibe a forma de assembly do código
  • -N: Desabilita otimização de compilação
  • -m: Exibe decisões de otimização
  • -l: Desabilita inline de função
  • -c: Número de processos simultâneos de compilação
  • -dwarf: Gera símbolos DWARF

Por exemplo, se quiser visualizar a forma de assembly do código, você pode usar o parâmetro -S e também desabilitar otimização e inline para restaurar sua forma original, como 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

Através de ldflags, você pode passar alguns parâmetros para o linkador para controlar comportamentos específicos. Use o seguinte comando para visualizar todos os valores disponíveis de ldflags, que são quase vinte ou trinta.

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

O parâmetro -X de ldflags é uma função muito prática que permite definir o valor de variáveis de string de pacotes especificados durante o link. Através desta função, podemos convenientemente injetar algumas metainformações durante a compilação. E como é apenas uma variável, também é conveniente obtê-la em tempo de execução. Aqui está um exemplo simples.

go
package main

import "fmt"

var (
  Version string
)

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

Executar comando

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

Após a execução, exibirá a soma de verificação sha1 do commit git.

5e3fd7a

Alguns outros parâmetros práticos incluem

  • -w: Não gera DWARF, que é uma informação conveniente para depuração de código-fonte.
  • -s: Desabilita tabela de símbolos

Estes dois são geralmente usados juntos e podem reduzir significativamente o tamanho do arquivo binário compilado, em cerca de 40%-50%. A desvantagem também é óbvia: não é possível depurar. Aqui está um exemplo.

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

Compilação Cruzada

A compilação da linguagem Go tem duas características principais: a primeira é a rapidez, e a outra é a compilação cruzada. Compilação cruzada significa que você pode compilar localmente código de destino para outros sistemas, como compilar arquivos binários para linux ou darwin no windows, e vice-versa. Muitas linguagens suportam compilação cruzada, o que não é nada surpreendente, mas a compilação cruzada da linguagem Go é muito simples, requerendo apenas as seguintes etapas

  1. Defina a variável de ambiente GOOS para selecionar seu sistema operacional de destino
  2. Defina a variável de ambiente GOARCH para selecionar sua arquitetura de CPU de destino
  3. Use go build para compilar como de costume

Todo o processo é muito rápido, sem necessidade de ferramentas ou configurações adicionais, e a velocidade é a mesma de sempre. Como mostrado abaixo

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

O primeiro passo SET CGO_ENABLED=0 desabilita o cgo. Uma vez que seu código use cgo, não será possível usar normalmente a compilação cruzada. O segundo passo SET GOOS define o sistema de destino, com opções linux, darwin, windows, netbsd. O terceiro passo define a arquitetura de CPU, SET GOARCH, com opções amd64, 386, arm, ppc64. O último passo é compilar como de costume.

Controle de Compilação

O comando build pode controlar a compilação através de tags, que existem no código-fonte como uma espécie de instrução. Veja um exemplo, arquivo product.go

go
// +build product

package main

import "fmt"

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

Arquivo debug.go

go
// +build debug

package main

import "fmt"

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

Ambos têm uma instrução // +build, indicando em que circunstâncias serão compilados. Seu formato básico é

go
// +build tag1 tag2

package pkg_name

Existem algumas regras que devem ser seguidas

  1. Deve haver um espaço entre // e +build
  2. Deve estar acima da declaração do pacote
  3. Deve haver uma linha em branco entre ele e a declaração do pacote

Além disso, também pode alcançar controle lógico através de espaçamento simples: espaço representa OR, vírgula representa AND, ! representa NOT. Por exemplo

go
// +build windows linux

package pkg_name

Indica que o arquivo atual será compilado nas plataformas windows ou linux.

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

package pkg_name

Este exemplo indica que será compilado apenas na plataforma windows com arquitetura amd64 e sem cgo habilitado, ou na plataforma linux com arquitetura i386 e cgo habilitado. Se você simplesmente não quiser que um arquivo participe da compilação, pode usar ignore.

go
// +build ignore

package pkg_name

Também pode haver múltiplas linhas de instruções

go
// +build windows
// +build amd64

package pkg_name

Instruções de múltiplas linhas são processadas de forma AND. Para tags como plataforma e arquitetura, o Go as passará automaticamente durante a compilação. Também podemos passar tags personalizadas. Usando os dois arquivos do início como exemplo

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

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

Como você pode ver, a saída é diferente quando diferentes tags são passadas, alcançando o objetivo de controle de compilação.

run

Os comandos run e build ambos compilam o código-fonte, mas a diferença é que o comando run executa diretamente após a compilação. Para acelerar a compilação, o comando run não gera informações de depuração durante o processo de compilação, portanto não suporta depuração, e gera apenas um arquivo binário temporário, geralmente armazenado no diretório GOTEMPDIR, como /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.

Também suporta as flags de compilação do comando build e fornece um parâmetro -exec para especificar qual programa deve executar o arquivo binário. [arguments...] refere-se aos parâmetros de execução do programa. Aqui está um exemplo

go
package main

import (
  "fmt"
  "os"
)

var (
  Version string
)

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

Usar go run para executar

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

No geral, o uso é muito semelhante ao go build, então não vou me alongar mais.

tool

O comando tool em si não tem nenhuma função. Sua função é chamar diretamente as ferramentas no diretório cmd/, por exemplo, cmd/compile é o compilador embutido. Através de go tool, você pode chamar diretamente essas ferramentas sem precisar executar manualmente os arquivos binários dessas ferramentas.

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

Use o parâmetro -n para imprimir todos os comandos suportados

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

Essas ferramentas estão localizadas no diretório GOROOT/pkg/tool e são agrupadas de acordo com o sistema operacional e arquitetura de CPU, como 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*

Use o formato go doc cmd/command para visualizar o uso de cada comando, por exemplo

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

As flags suportadas por cmd/compile são as mesmas mencionadas anteriormente para gcflags. A diferença entre go tool compile e go build é que o primeiro é apenas responsável pela compilação e só aceita arquivos como parâmetros, enquanto o último pode aceitar diretórios, pacotes e arquivos como parâmetros, e não apenas compila o código-fonte, mas também é responsável por linkar arquivos, limpar arquivos inúteis, etc. O primeiro é parte do último. Podemos imprimir os comandos executados durante o processo de 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
...

No processo, você pode ver que há /golang/pkg/tool/windows_amd64/compile.exe, que é a chamada do compilador. Além de compile, há muitas outras ferramentas que podem ser chamadas, e muitos comandos go são na verdade seus aliases.

clean

O comando clean é usado para limpar arquivos objeto gerados durante o processo de compilação

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

Suporta as seguintes flags

  • -i: Limpa os arquivos de arquivo ou binários correspondentes
  • -n: Imprime os comandos que serão executados durante o processo de limpeza, mas não os executa
  • -x: Imprime e executa os comandos que serão executados durante o processo de limpeza
  • -r: Limpa recursivamente através do import path
  • -cache: Limpa todo o cache gerado pelo go build
  • -testcache: Limpa todo o cache de teste gerado
  • -modcache: Limpa todo o cache de módulos baixados
  • -fuzzcache: Limpa o cache gerado pelo fuzz test.

Quando se usa go tool compile, chama-se diretamente o comando do compilador, sem fazer muito trabalho de limpeza como o go build, o que gera arquivos objeto. Por exemplo, executar o seguinte comando

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

Gerará um arquivo chamado main.o, que pode ser limpo usando o comando go clean. Ou use o parâmetro -n para imprimir os comandos que serão executados.

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

Limpar o cache de compilação removerá o cache de compilação gerado no diretório GOCACHE

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

Limpar o cache gerado pelo fuzz test, que é armazenado por padrão no diretório GOCACHE/fuzz/

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

fix

A linguagem Go já existe há dez anos até a escrita deste artigo. Durante o processo contínuo de atualização e modificação da linguagem, inevitavelmente surgem algumas incompatibilidades devido a mudanças de API. O comando fix foi criado para isso: ele detecta APIs obsoletas nos arquivos de código-fonte e as substitui por novas APIs.

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

Suporta diretórios, nomes de arquivos e caminhos como parâmetros, e recebe a flag -fix para passar parâmetros indicando que tipo de modificação deve ser feita. Você pode visualizar os valores disponíveis através do 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.

Aqui está um exemplo: o código-fonte usa o pacote golang.org/x/net/context

sh
package main

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

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

Use go fix para corrigir, substituindo pelo pacote context da biblioteca padrão. Podemos usar o seguinte comando para fazer a substituição

sh
$ go fix -fix context main.go

Também é possível não substituir e apenas visualizar as mudanças no arquivo.

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() {

A linguagem Go existe há mais de dez anos e tem apenas nove parâmetros de substituição disponíveis, o que mostra que a compatibilidade é mantida razoavelmente bem.

fmt

O comando fmt é a ferramenta de formatação embutida da linguagem Go, usada para formatar arquivos de código-fonte Go.

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

Use o comando go doc gofmt para visualizar sua documentação detalhada

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 usa tab para indentação e espaços para alinhamento. Por padrão, o código formatado será exibido na saída padrão, não sobrescrevendo o arquivo original. O comando go fmt na verdade usa o comando gofmt, que é um arquivo binário independente localizado no diretório GOROOT/bin.

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

Adicionar a flag -n ao comando go fmt permite saber quais comandos serão executados.

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

Como você pode ver, go fmt é na verdade um alias de gofmt -l -w. O comando gofmt possui os seguintes parâmetros

  • -d: Exibe as diferenças antes e depois da formatação
  • -e: Exibe todos os erros
  • -l: Exibe os nomes dos arquivos que foram modificados
  • -r: Aplica regras de formatação
  • -s: Tenta simplificar o código
  • -w: Sobrescreve o arquivo de origem. Se ocorrer um erro, restaura o backup

Suponha que agora tenhamos o seguinte arquivo de código-fonte

go
$ cat main.go
package main

import "fmt"

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

Use o parâmetro -d para visualizar as mudanças

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!")
+}

O parâmetro -l exibirá os nomes dos arquivos que serão modificados

$ gofmt -l .
main.go

Se houver erros de sintaxe, o parâmetro -e pode exibir de forma mais detalhada

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 aplicará as modificações ao arquivo de origem

sh
$ gofmt -l -w .
main.go

$ cat main.go
package main

import "fmt"

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

Você pode notar que, como ferramenta de formatação, gofmt não fornece nenhuma configuração personalizada. Em contraste, o formatador prettify para código js fornece muitas configurações para formatação de código. Isso reflete a atitude oficial do Go: não queira fazer personalizações, o estilo de código de todos deve ser o mesmo, pelo menos há uma vantagem: não é necessário se adaptar aos hábitos de outras pessoas ao ler código. No entanto, ainda保留了 uma personalização: as regras de substituição de código formatado podem ser personalizadas, no formato a seguir

pattern -> replacement

Por exemplo, remover parênteses redundantes

(a) -> a

Visualizar mudanças no arquivo

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

Como você pode ver, gofmt removerá os parênteses redundantes.

get

O comando get é absolutamente o mais usado durante o desenvolvimento Go. Sua função é baixar o código-fonte do pacote do endereço especificado para o diretório correspondente de GOMODCACHE.

sh
$ go get -h
usage: go get [-t] [-u] [-v] [build flags] [packages]
Run 'go help get' for details.
  • -u: Tenta atualizar a versão secundária e a versão de correção do pacote. Se envolver mudança de versão principal, como v1->v2, não será atualizado.
  • -t: Atualiza a versão das dependências nos testes
  • -v: Exibe os pacotes compilados, na verdade é um dos parâmetros de build flags

Nos primeiros dias, go get era similar ao go install: baixava e compilava esses pacotes. No entanto, com o surgimento e aperfeiçoamento dos módulos Go, essa função foi gradualmente descontinuada. Agora, a função mais comum do comando get é baixar e resolver dependências para módulos Go. Portanto, você pode ver que o comando go get ainda suporta flags de compilação como build flags. E se você tentar usar go get fora de um módulo como usaria go install, ele avisará que este uso foi descontinuado.

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'.

Não se sabe por que essas descrições ainda são mantidas na documentação. Ao examinar o código-fonte do comando get, você descobrirá que ele mantém as flags antigas.

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
)

Voltando ao assunto, o comando get baixará o código-fonte do pacote especificado para o diretório de dependências global local, que é o diretório correspondente a GOCACHE, e então registrará as informações nos arquivos go.mod e go.sum. O primeiro é responsável por registrar a versão, e o segundo é responsável por registrar a soma de verificação sha1 para garantir segurança. O comando get é na verdade baseado em VCS, ou seja, sistema de controle de versão local, e suporta os seguintes

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

Dentre eles, por padrão, apenas git e hg são suportados, podendo ser configurado em GOVCS, no formato a seguir

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

GOVCS suporta apenas git e hg como VCS. Os outros três precisam ser configurados em GOPRIVATE.

O comando go get tem os seguintes usos: pode usar diretamente o endereço da dependência como parâmetro

sh
$ go get golang.org/x/net

Também é possível especificar uma versão

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

Especificar a versão mais recente

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

Tentar atualizar a versão

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

Remover uma dependência

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

Os usos acima são para gerenciar dependências comuns. Também pode ser usado para gerenciar dependências menos comuns, como atualizar a versão da linguagem 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

Até mesmo pode ser usado para atualizar a versão da cadeia de ferramentas Go

sh
$ go get toolchain@latest

Quando você usa go get para atualizar as versões do Go e da cadeia de ferramentas, eles instalarão a nova versão do Go no diretório GOMODCACHE/golang.org/

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

Neste ponto, modificar manualmente GOROOT permitirá alternar para a versão especificada.

install

O comando install é similar ao comando get, ambos são usados para baixar dependências de terceiros, mas a diferença é que o comando get baixa o código-fonte, enquanto o comando install compila o código-fonte em um arquivo binário executável nativo. O caminho de armazenamento do arquivo binário é primeiro no diretório GOBIN e depois em GOPATH/bin. A principal função deste comando é baixar algumas ferramentas de linha de comando públicas de terceiros. Graças à velocidade de compilação e portabilidade da linguagem Go, não é necessário baixar arquivos binários, mas sim baixar o código-fonte e compilá-lo localmente.

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

O comando install recebe flags de compilação e nomes de pacotes como parâmetros. Com o gomod habilitado, o nome do pacote deve incluir o número da versão. Por exemplo, baixar o depurador 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/

Primeiro, ele baixará o código-fonte para o caminho armazenado em GOMODCACHE, o que é o mesmo que o comando get. Em seguida, muda para o diretório de trabalho temporário para compilá-lo. Após a compilação, move o arquivo binário para o diretório GOPATH/bin e finalmente exclui a pasta temporária. O comando install também tem uma restrição: o pacote baixado deve ser o pacote de entrada do projeto, ou seja, deve conter o arquivo de entrada main.go, caso contrário, avisará que não pode ser instalado. Por exemplo, usar go install para baixar o 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 é uma biblioteca de dependência de framework web, não é uma ferramenta de linha de comando, naturalmente não tem arquivo de entrada, então a instalação falhará.

list

O comando list lista pacotes em locais especificados, um por linha, e suporta saída formatada personalizada. Suporta muitos parâmetros, e seu uso requer estar em um projeto que suporte gomod.

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

Os parâmetros suportados são os seguintes

  • -f: Parâmetro de formatação
  • -json: Saída no formato json
  • -compiled: Exibe todos os pacotes que serão compilados pelo compilador
  • -deps: Exibe cada pacote e o nome de cada pacote do qual depende
  • -test: Exibe o pacote de teste de cada pacote
  • -e: Saída normal ao encontrar pacotes com erro
  • -find: Não analisa as relações de dependência desses pacotes
  • -export: Ao usar este parâmetro, define o valor do campo Package.Export da struct como o arquivo contendo as informações de exportação mais recentes do pacote especificado, e define o valor do campo Package.BuildID como o BuildID do pacote, principalmente para saída formatada.

Parâmetros de informações de módulo:

  • -m: Exibe módulos em vez de pacotes

  • -versions: Exibe todas as informações disponíveis de um módulo

  • -retracted: Exibe versões retraídas de um módulo

O parâmetro [packages] pode ser um nome de pacote especificado, ou um diretório, ou all, que significa qualquer lugar. Ao usar o parâmetro -m, all significa todas as dependências referenciadas pelo módulo atual.

Por exemplo, atualmente há apenas um arquivo main.go no diretório, e há apenas uma linha de código que exibe "hello world". Após executar go list -deps ., ele exibe todos os pacotes de dependência desde o projeto atual até fmt e suas referências.

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

Ou exibe todas as dependências de módulo do projeto atual

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

A saída do comando list é por linha, e cada linha de saída é um pacote. A equipe oficial fornece o parâmetro -f para personalizar o formato de saída de linha. O valor que ele aceita é a sintaxe de template definida pelo pacote de motor de template template/text, por exemplo

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

Cada pacote iterado será passado na forma da seguinte struct, e todos os campos desta struct podem ser usados como parâmetros de 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 iterando módulos, será passado na forma da seguinte struct, e todos os seus campos também podem ser usados como parâmetros de 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
}

Visualizar todos os pacotes

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

Visualizar módulos

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

mod

go mod é um comando dedicado ao gerenciamento de módulos 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.

Possui os seguintes subcomandos

  • download: Baixa todas as dependências declaradas no arquivo go.mod para o cache local
  • edit: Edita o arquivo go.mod. A interface de linha de comando fornecida é principalmente para uso por outras ferramentas ou scripts.
  • init: Inicializa um projeto gomod no diretório atual
  • tidy: Baixa dependências ausentes e remove dependências não utilizadas
  • graph: Exibe o gráfico de dependências
  • verify: Verifica dependências locais
  • why: Explica por que esses módulos são dependentes
  • vendor: Exporta dependências do projeto para o diretório vendor

init

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

O comando init é usado para inicializar um projeto gomod. Seu único parâmetro é o caminho do módulo, que será usado como base para que outras pessoas baixem suas dependências no futuro. Sua regra de nomenclatura geral é

domain_name/user_name/repo_name

Por exemplo, como a maioria das pessoas coloca seus projetos no github, pode ser

github.com/jack/gotour

Não é recomendado usar símbolos especiais como caminho de módulo. Aqui está um exemplo de 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]

O comando tidy limpará as dependências não utilizadas no go.mod, ou seja, dependências que não são referenciadas, e baixará as dependências que são referenciadas mas não existem. Suporta os seguintes parâmetros

  • -v: Exibe as dependências de módulo que foram removidas
  • -e: Ignora erros durante o processo e continua a execução
  • -x: Exibe o processo de execução
  • -go=version: Atualiza a versão do Go no arquivo go.mod
  • -compat=version: Mantém quaisquer somas de verificação adicionais necessárias da versão principal do Go especificada para carregar com sucesso o gráfico de módulos, e se o comando go desta versão carregar qualquer pacote importado de uma versão de módulo diferente, causará erro no tidy. Este parâmetro raramente é usado, geralmente causa erros apenas durante mudanças de versão. Você pode ver esta resposta no stackoverflow: go modules - go mod tidy error message: "but go 1.16 would select" - Stack Overflow

Veja um exemplo de uso

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]

Embora o nome do comando download seja traduzido como download, ele apenas baixa as dependências para o cache de dependências local e não modifica o arquivo go.mod. Sua função é pré-baixar dependências para o cache de arquivos local. Se você quiser baixar uma dependência específica, é recomendado usar go get ou go mod tidy.

Aqui estão alguns exemplos de uso

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)

Se executado sem parâmetros, ele baixará todas as dependências que existem no arquivo go.mod mas não existem no cache de dependências local. Se não houver nada para baixar, ele exibirá

go: no module dependencies to download

edit

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

edit é uma interface de linha de comando para modificar o arquivo go.mod, geralmente usada por outros programas. Alguns editores e IDEs usam esses comandos para fornecer suporte a gomod. Suporta os seguintes parâmetros

  • -module: Modifica o caminho do módulo
  • -go=version: Modifica a versão esperada do Go
  • -require=path@version: Adiciona uma dependência
  • -droprequire=path@version: Remove uma dependência
  • -exclude=path@version: Adiciona uma dependência de exclusão
  • -dropexclude=path@version: Remove uma dependência de exclusão
  • -replace=old@version=new@version: Adiciona uma dependência de substituição
  • -dropreplace=old@version: Remove uma dependência de substituição
  • -retract=version: Adiciona um item de retração de versão
  • -dropretract=version: Remove um item de retração de versão

Há também outros parâmetros para exibição

  • -print: Exibe o conteúdo do arquivo
  • -json: Exibe no formato json

Por exemplo

$ 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]

O comando graph exibirá o gráfico de dependências do projeto atual. Sua legibilidade é muito ruim e na maioria das vezes não é destinado a leitura humana. Os resultados geralmente são processados e exibidos de forma visualizada. Cada linha é uma dependência, no formato a seguir

引用方 被引用方

Por exemplo

golearn go@1.21.3

Também suporta dois parâmetros

  • -go=version: Usa a versão do Go especificada para carregar o gráfico de dependências. O valor não pode ser menor que a versão no arquivo go.mod.
  • -x: Exibe os comandos executados durante o processo.

Veja um exemplo de uso simples

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 é uma alternativa ao gopath antes do lançamento do gomod. Cada projeto Go terá um diretório vendor, armazenando as dependências de cada projeto no formato domain/user/project, assim como o inchado node_module do Node.js, onde as dependências de cada projeto são armazenadas separadamente. Esta maneira de gerenciar dependências parece realmente estúpida agora, mas na época não havia uma solução melhor. A razão para manter o vendor é porque o Go mantém a promessa de compatibilidade com versões anteriores. Alguns projetos antigos, incluindo o código-fonte do Go, podem ainda estar usando vendor.

Voltando ao assunto, vendor é um subcomando do go mod que pode exportar as dependências globais referenciadas pelo módulo atual para o diretório vendor.

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

Possui os seguintes parâmetros

  • -o: Especifica o caminho da pasta de saída
  • -v: Exibe cada dependência
  • -e: Não sai ao encontrar erros, continua

Veja um exemplo. Primeiro use go list -m all para visualizar as dependências referenciadas pelo projeto atual

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

Exporte para o diretório vendor atual

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

A estrutura de diretórios após a exportação é a seguinte

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

O modules.txt é o arquivo que descreve todas as dependências, semelhante ao atual go.mod.

verify

sh
$ go help mod verify
usage: go mod verify

Este comando verificará se as dependências do projeto foram modificadas após serem baixadas para o local. Por exemplo, se não houver problemas, exibirá all modules verified

sh
$ go mod verify
all modules verified

Caso contrário, ele reportará onde ocorreram mudanças e terminará o comando com status anormal. Por exemplo

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

Explica por que este pacote é dependente, na verdade exibe o gráfico de dependências relacionado a ele. Por exemplo

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

Por padrão, apenas analisará as importações de main. Adicionar o parâmetro -m pode analisar a situação de importação de cada pacote.

work

O comando work é uma ferramenta de desenvolvimento local para gerenciamento de múltiplos módulos 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

O subcomando init é usado para inicializar um workspace. Este comando criará um arquivo chamado go.work

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

Recebe o parâmetro [moddirs] para especificar quais módulos serão gerenciados, por exemplo

bash
$ go work init ./service ./api

use

O subcomando use é usado para adicionar diretórios de módulos gerenciados ao 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.

Recebe [moddirs] como parâmetro, e há uma flag -r que indica para pesquisar recursivamente por módulos no caminho [moddirs], por exemplo

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

edit

A função do subcomando edit é a mesma de go mod edit, ambos são deixados para interfaces de linha de comando para outras ferramentas e scripts operarem.

$ 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

Os parâmetros são os seguintes

  • -fmt: Formata o arquivo go.work

  • -use, -dropuse: Adiciona e remove caminhos de módulo

  • -replace=old[@v]=new[@v], -dropreplace=old[@v]=new[@v]: Usado para adicionar e remover módulos a serem substituídos

  • -go, -toolchain=name: Especifica a versão do Go e a cadeia de ferramentas a ser usada

  • -print: Imprime as modificações finais sem gravar de volta no arquivo

  • -json: Exibe no formato json, não pode ser usado com -print simultaneamente. A estrutura de tipo correspondente é a seguinte

    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
    }

Alguns exemplos de uso são os seguintes: saída formatada

bash
$ go work edit -fmt -print
go 1.22.0

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

Saída json

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

sync

O subcomando sync é usado para sincronizar a lista de módulos no go.work de volta aos vários módulos no workspace.

bash
$ go help work sync
usage: go work sync

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

Este processo ocorre principalmente após a conclusão do desenvolvimento local, quando cada módulo já completou o trabalho de lançamento. Neste ponto, usar sync atualizará as dependências no go.mod de todos os módulos no workspace de acordo com as relações de dependência de cada módulo, eliminando a necessidade de atualização manual.

vendor

O comando vendor copiará todas as bibliotecas dependentes de todos os módulos no workspace para o diretório vendor.

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

A função é a mesma de go mod vendor, não vou me alongar mais.

vet

O comando vet é uma ferramenta de verificação estática de erros de código-fonte da linguagem Go, assim como ferramentas lint de outras linguagens, como 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.

Vamos ver um exemplo simples. Existe o seguinte código-fonte

sh
$ cat main.go
package main

import "fmt"

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

Execute go vet sem parâmetros no mesmo diretório

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

vet reportará qual arquivo, qual linha e qual é o problema. Suporta flags de compilação como parâmetros, como -n e -x, e suporta pacotes, diretórios e nomes de arquivos como parâmetros.

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

Use o seguinte comando para visualizar seus parâmetros e explicações mais detalhados.

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

O comando go tool vet não pode ser usado diretamente para verificar código. Deve-se usar go vet. Os [vet flag] nos parâmetros do go vet suportam a configuração de analisadores de código. Os valores disponíveis são os seguintes

asmdecl      检查汇编文件是否与 go 声明不匹配
assign       检查是否有无用的变量
atomic       检查使用 sync/atomic 时是否破坏了原子性
bools        检查是否错误使用逻辑运算符
buildtag     检查 build tag
cgocall      检查违反 cgao 指针传递规则的行为
composites   检查未初始化的复合结构,比如 map,chan
copylocks    检查是否发生了锁的值复制
directive    检查 go 工具链指令
errorsas     检查是否向 errors.As 传递非指针类型或非 error 类型的值
framepointer 检查编译优化后的汇编代码是否在保存帧指针之前对其进行清除
httpresponse 检查是否错误使用 httpresponse
ifaceassert  检查接口到接口的类型断言
loopclosure  循环变量的引用问题
lostcancel   context.WithCancel 没有使用 cancel 函数
nilfunc      检查函数和 nil 之间是否存在无用的比较
printf       检查 printf 的格式化参数是否正确
shift        检查是否有等于或超过整数宽度的移位
sigchanyzer  检查无缓冲的 chan os.Signal
slog         检查不合法的结构化日志调用
stdmethods   检查已知接口方法的签名是否正确
stringintconv 检查字符串整型转换
structtag    检查结构体 tag 是否正确
testinggoroutine 检查是否在测试中使用协程调用 testing.Fatal
tests        检查测试和示例的常见错误用法
timeformat   使用 (time.Time).Format 或 time.Parse 的时间格式是否正确
unmarshal    向 unmarshal 传递非指针或非接口类型
unreachable  检查不可到达的代码
unsafeptr    检查 uintptr 到 unsafe.Pointer 不正确转换
unusedresult 检查未使用的函数返回值

Todos são analisadores que analisam um ponto específico. Por exemplo, o analisador timeformat verifica se a chamada de time.Format está em conformidade com a sintaxe correta. Por padrão, todos os analisadores acima serão habilitados. Para habilitar individualmente, use o seguinte formato

sh
$ go vet -timeformat main.go

Para desabilitar individualmente

sh
$ go vet -timeformat=false main.go

O código-fonte desses analisadores está localizado em cmd/vendor/golang.org/x/tools/go/analysis/passes. Cada analisador é uma armadilha comum na linguagem Go, por isso é altamente recomendado usar o comando vet para verificar seu código. Além disso, também suporta algumas outras flags

  • -V: Apenas imprime a versão e sai
  • -json: Exibe no formato json
  • -c=n: Exibe o número especificado de linhas de conflito no contexto (parece não ter nenhum efeito)

Também há alguns analisadores externos, como shadows, que é responsável por detectar problemas de ocultação de variáveis com nomes curtos. Como é externo, precisa ser baixado usando go install

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

O formato de uso é o seguinte

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.

O comando test é o comando da cadeia de ferramentas da linguagem Go que fornece funcionalidade de teste. Esta função é muito importante. Para um software, testes completos são indispensáveis. Aqui apenas introduziremos brevemente como usar o comando test. Se quiser saber mais sobre testes, visite: 测试

Além de suportar os parâmetros de compilação do comando build, o test também suporta os seguintes parâmetros

  • -args: Parâmetros de entrada do programa
  • -c: Compila o arquivo binário de teste do pacote atual para o diretório atual, mas não executa, nomeando como pkg.test
  • -exec: Executa alguns outros comandos antes do início do teste
  • -json: O estilo de saída do teste se torna json
  • -o: Especifica o caminho do arquivo binário de teste

Também suporta muitas testflag. Use o comando help para visualizar todas as testflag

sh
$ go help testflag
`go test` 命令既接受作用于 `go test` 本身的标志,
也接受作用于生成的测试二进制文件的标志。

`go test` 命令识别以下标志,并用于控制任何测试的执行:
        -bench regexp
        -benchtime t
        -count n
    ......

Apresentamos alguns comumente usados

  • -v: Exibe os resultados de teste de cada caso de uso.
  • -timeout duration: Tempo limite de execução do teste
  • -skip regexp: Pula os casos de teste especificados
  • -short: Faz com que casos de teste que levam muito tempo sejam executados de forma mais curta
  • -shuffle: Embaralha a ordem de execução de todos os casos de teste
  • -run regexp: Executa os casos de teste especificados
  • -list regexp: Lista cada caso de teste
  • -cpu 1,2,4: Especifica o número de CPUs
  • -count n: Especifica quantas vezes cada caso de teste deve ser executado

O uso mais simples é sem parâmetros, que executará todos os casos de teste no pacote atual e exibirá os resultados.

sh
$ ls *_test.go
hello_test.go

$ go test
PASS
ok      golearn 0.522s

Especificar um arquivo de teste

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

Adicionar o parâmetro -v permite visualizar saída mais detalhada, o que é muito comum.

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

Especificar um caso de teste

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

Durante o teste, o comando test tem dois modos. Primeiro, vamos falar sobre o modo de diretório. Quando o comando test é executado sem o parâmetro package, ele executará o teste no modo de diretório, como os seguintes comandos

sh
$ go test
$ go test -v

Neste modo, o cache de teste é desabilitado. O outro modo é o modo de lista. Quando o parâmetro package não está vazio, o teste será executado no modo de lista. A diferença entre ele e o anterior é se o cache de teste está habilitado. Por exemplo

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

No modo de lista, o Go compilará os arquivos de teste de cada pacote no pacote especificado em arquivos binários e os executará. Para evitar executar testes repetidamente, o Go armazenará os resultados em cache por padrão e não recompilará na segunda execução. O cache será habilitado por padrão ao usar os seguintes parâmetros

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

Usar outros parâmetros além destes pode desabilitar o cache. O método recomendado oficialmente é usar -count=1 para desabilitar o cache. Por exemplo

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

Diretivas

Diferentemente dos comandos, as diretivas do Go existem no código-fonte de forma hard-coded. Elas têm outro nome mais técnico: diretivas de pragma (pragma directives).

Compiladores e linkers mudarão seu comportamento devido a elas, alcançando assim o controle de compilação, um pouco como macros em linguagem C. Claro, nem todas as diretivas são usadas para influenciar a compilação. Algumas são usadas para outros comportamentos funcionais. Por exemplo, a diretiva generate é geralmente usada para funcionalidade de geração de código. Essas diretivas geralmente existem na forma de comentários e têm //go: como prefixo, sem nenhum espaço no meio, como a diretiva //go:generate. Todos os tipos de diretivas são divididos em dois tipos

  • Diretivas funcionais: Estas são diretivas funcionais fornecidas pelo Go que podem ser usadas livremente, como generate, embed, build.
  • Diretivas de compilador: Estas diretivas precisam ser usadas com cuidado. Uso indevido pode levar a resultados imprevisíveis.

Exceto pelas diretivas funcionais, a maioria das diretivas só pode atuar em assinaturas de função. Para diretivas de compilador, execute o comando go doc compile para visualizar suas diretivas. Para todas as diretivas, você pode encontrar informações sobre elas em 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]

A diretiva generate, como o nome sugere, está relacionada à geração. Geralmente, sua função é executar comandos que geram código e atualizam código-fonte, mas na verdade pode executar qualquer comando. Além disso, diferentemente de outras diretivas, generate tem um comando dedicado que pode executar todas as diretivas generate localizadas em arquivos de código-fonte. Pode usar nomes de arquivos ou nomes de pacotes como parâmetros de entrada para indicar em quais arquivos executar as diretivas generate. Aqui estão seus outros parâmetros.

  • -run=regex: Executa as diretivas generate especificadas
  • -skip=regex: Pula as diretivas generate especificadas
  • -n: Imprime os comandos que serão executados
  • -x: Imprime os comandos executados durante o processo
  • -v: Exibe os arquivos processados

Além disso, os comandos executados na diretiva generate também suportam os seguintes parâmetros embutidos

  • $GOARCH: Arquitetura da CPU
  • $GOOS: Sistema operacional
  • $GOFILE: Nome do arquivo
  • $GOLINE: Número da linha
  • $GOPACKAGE: Nome do pacote
  • $GOROOT: Go root
  • $DOLLAR: Símbolo de dólar
  • $PATH: Variável de ambiente path

Veja um exemplo: sem código, apenas um comentário

go
package main

//go:generate echo "hello world!"

Executar comando

$ go generate .
hello world!

Este exemplo executa um comando go

go
package main

//go:generate go version

Executar comando

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

A diretiva generate pode ser usada para executar qualquer comando, como swagger para gerar documentação de API, ou Wire para gerar código IOC. No entanto, esta diretiva não é adequada para executar comandos muito complexos. É adequada para executar comandos curtos. Se houver requisitos complexos, pode-se usar scripts ou makefile como substituto.

embed

A diretiva embed foi adicionada na versão 1.16. Sua função é empacotar arquivos estáticos junto com o arquivo binário, como templates HTML, por exemplo. Seu formato é o seguinte

go
//go:embed pattern

pattern pode ser uma expressão glob, um diretório ou um arquivo específico. Veja um exemplo

go
package main

import "embed"

//go:embed *
var static embed.FS

A diretiva embed requer que esteja localizada acima de uma variável global do tipo embed.FS. Note que deve ser uma variável global, e é necessário importar o pacote embed para usá-la. Neste exemplo, * representa que todos os arquivos no diretório atual serão empacotados no arquivo binário, mas não permitirá diretórios que começam com ..

O exemplo a seguir mostra como ler conteúdo de arquivos embutidos

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

Possui apenas três métodos, e o uso não é diferente de um sistema de arquivos comum. Além disso, como implementa a interface io/Fs, também pode ser passado como um objeto 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)

O exemplo a seguir mostra como embutir um arquivo html através da diretiva embed e acessá-lo através de um serviço 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)
}

O resultado do acesso é o seguinte

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>

A diretiva embed também suporta que o tipo da variável global seja []byte. Veja o exemplo a seguir

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

O efeito implementado é semelhante ao exemplo anterior.

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

Na seção build-Controle de Compilação, falamos sobre como usar a diretiva // +build para controlar o comportamento de compilação. A diretiva //go:build foi lançada na versão 1.17, com a intenção de substituir a diretiva anterior, mas agora na versão 1.21 ainda não foi substituída. Estima-se que existirá de forma coexistente no futuro. Sobre esta nova diretiva, a documentação oficial também tem uma introdução: build constraints. Sua função não é muito diferente da anterior, mas a sintaxe é mais rigorosa e suporta expressões booleanas. Veja um exemplo

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

package pkg_name

Esta maneira tem legibilidade muito maior do que a anterior.

line

A diretiva line afetará o número da linha, número da coluna e nome do arquivo da próxima linha. Sua função se limita a isso, e na maioria das vezes pode ser usada para depurar erros, por exemplo. Ao ocorrer um erro, mudará as informações de saída do compilador.

go
package main

var a undefinedType

func main() {

}

Normalmente, o compilador exibirá

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

Mas se usar a diretiva line, será diferente

go
package main

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

func main() {

}

Então sua saída será

abc.go:10:106: undefined: undefinedType

E devido a razões históricas, a diretiva line é a única diretiva com uso diferente das outras. Seu formato é

go
//line filename:line:column

Como você pode ver, não requer go: como prefixo.

linkname

Esta operação de diretiva pode ser usada para linkar funções ou variáveis globais de outros pacotes, mesmo que sejam tipos privados. Esta operação frequentemente aparece na biblioteca padrão, especialmente em runtime. Algumas funções sem corpo são implementadas através desta maneira, e outra parte das funções com corpo vazio é implementada por assembly. Vamos ver seu uso. O formato de uso é o seguinte

go
//go:linkname nome_do_tipo_linkado tipo_linkado

E antes de usar, por exemplo, importe o pacote unsafe. Veja um exemplo simples de linkar um tipo privado na biblioteca padrão

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

Saída

15395306441938000233

Ela linkou a função privada runtime.memhash com a função que declaramos. Esta função não tem corpo, apenas uma assinatura, servindo apenas como um veículo. A função memhash serve para calcular o valor hash com base na memória, dado um ponteiro, semente de hash e offset de memória. Este processo de link é concluído durante o período de compilação.

Se não for da biblioteca padrão, a situação é um pouco diferente. Por exemplo, há uma função test no pacote example. Antes de linkar, é necessário importar anonimamente este pacote.

go
package example

// Um tipo privado, inacessível do exterior.
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())
}

Saída

a

Como você pode ver, o link foi bem-sucedido. Este método pode contornar o sistema de módulos do Go e fazer o que quiser, mas não é recomendado usar em larga escala, a menos que você saiba o que está fazendo.

noinline

A diretiva noinline indica que uma função é proibida de otimização de inline, mesmo que seja muito simples. Veja um exemplo simples

go
package main

func val() string {
  return "val"
}

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

val é uma função muito simples que retorna um literal de string. Como é muito simples e o resultado é sempre previsível, durante a compilação será otimizada pelo compilador para a seguinte forma

go
package main

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

Vamos ver como é em assembly. Como você pode ver, não há chamada para a função 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

Agora adicione a diretiva noinline

go
package main

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

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

Vamos ver sua forma de 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

Desta vez, você pode ver muito claramente a chamada main.val, e esta é exatamente a função da diretiva noinline: impedir o inline de função durante a otimização do compilador.

nosplit

A diretiva nosplit serve para pular a detecção de estouro de pilha. Como o modelo de agendamento concorrente do Go é um agendamento preemptivo, se uma função executar código de nível muito baixo e outras goroutines não forem adequadas para serem preemptadas ao chamar esta função, pode-se usar esta diretiva para indicar.

go
//go:nosplit
func nospilitFn()

Após usar esta diretiva, não haverá mais crescimento de pilha.

noescape

noescape, como o nome sugere facilmente, está relacionado a escape. Sua função é indicar que a função atual não terá comportamento de escape de memória. Após a execução, todos os recursos serão recuperados, e esta função deve ter apenas assinatura sem corpo. Neste caso, geralmente a implementação da função é feita em assembly.

Por exemplo, memhash usado anteriormente usará esta diretiva

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

Desta forma, o compilador não realizará análise de escape nela. A premissa é que você deve garantir que não ocorra escape. Se ocorrer, não se sabe quais serão as consequências.

uintptrescapes

A diretiva uintptrescapes indica que o parâmetro do tipo uintptr nesta função foi convertido para um valor de ponteiro e escapou para o heap, e deve ser mantido vivo. Esta diretiva é geralmente usada para algumas chamadas de sistema de baixo nível. Na maioria dos casos, não é necessário entendê-la.

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

Anteriormente, deveria haver uma diretiva notinheaps usada para indicar que um tipo não permite alocação de memória no heap, mas não se sabe em qual versão foi removida.

norace

A diretiva norace indica que o acesso à memória de uma função não requer mais análise de corrida. Geralmente é usada ao executar código de baixo nível onde não é adequado realizar análise de corrida.

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

TIP

Algumas diretivas são limitadas para uso apenas pelo pacote runtime, e não podem ser usadas externamente. Elas envolverão coisas mais profundas. Se quiser entender, você pode ver informações sobre elas em Runtime-only compiler directives.

Golang por www.golangdev.cn edit