Saiba mais sobre pacotes

Concluído

Os pacotes do Go são como bibliotecas ou módulos em outras linguagens de programação. Você pode empacotar o código e reutilizá-lo em outro lugar. O código-fonte de um pacote pode ser distribuído em mais de um arquivo .go. Até agora, escrevemos o pacote main e fizemos algumas referências a outros pacotes nativos.

Nesta seção, você aprenderá o que é um pacote. Também verá como criar um e como consumir pacotes externos.

Pacote principal

Como você deve ter observado, até mesmo o programa mais simples no Go precisa fazer parte de um pacote. Normalmente, o pacote padrão é o pacote main, aquele que estamos usando até agora. Se um programa fizer parte do pacote main, o Go vai gerar um arquivo binário. Quando esse arquivo é executado, ele chama a função main().

Em outras palavras, quando você usa o pacote main, o programa produzirá um executável autônomo. Mas quando um programa faz parte de um pacote diferente de main, o Go não gera um arquivo binário. Ele gera um arquivo de pacote (um arquivo com a extensão .a).

Na linguagem Go, os nomes dos pacotes seguem uma convenção. Um pacote usa a última parte do respectivo caminho de importação como nome. Por exemplo, a biblioteca padrão da linguagem Go contém um pacote chamado math/cmplx, que fornece um código útil para trabalhar com números complexos. O caminho de importação desse pacote será math/cmplx. Além disso, ele deverá ser importado do seguinte modo:

import "math/cmplx"

Para se referir a objetos no pacote, use o nome do pacote, cmplx, do seguinte modo:

cmplx.Inf()

Vamos criar um pacote.

Criar um pacote

Crie um diretório no diretório $GOPATH/src chamado calculator. Crie um arquivo chamado sum.go. O diretório de árvore será parecido com este diretório:

src/
  calculator/
    sum.go

Inicialize o arquivo sum.go com o nome do pacote:

package calculator

Agora você pode começar a escrever as funções e as variáveis para o pacote. Ao contrário de outras linguagens de programação, o Go não fornece as palavras-chave public ou private para indicar se uma variável ou uma função pode ser chamada de fora ou dentro do pacote. No entanto, o Go segue duas regras simples:

  • Caso deseje que algo seja particular, inicie o nome dele com uma letra minúscula.
  • Caso deseje que algo seja público, inicie o nome dele com uma letra maiúscula.

Portanto, vamos adicionar o seguinte código ao pacote de calculadora que estamos criando:

package calculator

var logMessage = "[LOG]"

// Version of the calculator
var Version = "1.0"

func internalSum(number int) int {
    return number - 1
}

// Sum two integer numbers
func Sum(number1, number2 int) int {
    return number1 + number2
}

Vejamos algumas coisas nesse código:

  • A variável logMessage pode ser chamada somente de dentro do pacote.
  • A variável Version pode ser acessada em qualquer lugar. Recomendamos que você inclua um comentário para descrever a finalidade dessa variável. (Essa descrição é útil para qualquer pessoa que usa o pacote.)
  • A função internalSum pode ser chamada somente de dentro do pacote.
  • A função Sum pode ser acessada em qualquer lugar. Recomendamos incluir um comentário para descrever a finalidade da função.

Para confirmar se tudo está funcionando, execute o comando go build no diretório calculator. Se você fizer isso, observe que nenhum binário executável é gerado.

Criar um módulo

Você inseriu a funcionalidade de calculadora em um pacote. Agora é preciso inserir esse pacote em um módulo. Os módulos da linguagem Go geralmente contêm pacotes que oferecem uma funcionalidade relacionada. O módulo de um pacote também especifica o contexto em que a linguagem Go precisa estar para executar o código agrupado. Essas informações contextuais incluem a versão do Go para a qual o código foi escrito.

Além disso, os módulos ajudam outros desenvolvedores a referenciar versões específicas do código e facilitam o trabalho com as dependências. Outro benefício é que o código-fonte do nosso programa não precisa estar estritamente no diretório $GOPATH/src. A liberação dessa restrição torna mais conveniente trabalhar com diferentes versões de pacote em outros projetos ao mesmo tempo.

Portanto, para criar um módulo para o pacote calculator, execute este comando no diretório raiz ($GOPATH/src/calculator):

go mod init github.com/myuser/calculator

Após executar esse comando, github.com/myuser/calculator se tornará o nome do módulo. Você usará esse nome para referenciá-lo em outros programas. O comando também cria um arquivo chamado go.mod. Por fim, o diretório de árvore agora ficará parecido com este diretório:

src/
  calculator/
    go.mod
    sum.go

O conteúdo do arquivo go.mod será semelhante ao código a seguir. (A versão do Go pode ser diferente.)

module github.com/myuser/calculator

go 1.14

Para fazer referência ao pacote calculator em outros programas, será preciso importá-lo usando o nome do módulo. Nesse caso, o nome é github.com/myuser/calculator. Agora, vejamos um exemplo de como usar esse pacote.

Observação

Historicamente, o gerenciamento de dependências no Go não é fácil. O sistema de gerenciamento de dependências ainda é um trabalho em andamento. Caso deseje saber mais sobre os módulos, confira esta série de postagens publicadas no blog do Go.

Referenciar um pacote local (um módulo)

Agora, vamos usar o pacote. Continuaremos com o aplicativo de exemplo que estamos usando. Desta vez, em vez de ter a função sum no pacote main, vamos usar a que criamos anteriormente no pacote calculator.

A estrutura do arquivo de árvore agora será parecida com esta:

src/
  calculator/
    go.mod
    sum.go
  helloworld/
    main.go

Usaremos este código para o arquivo $GOPATH/src/helloworld/main.go:

package main

import (
  "fmt"
  "github.com/myuser/calculator"
)

func main() {
    total := calculator.Sum(3, 5)
    fmt.Println(total)
    fmt.Println("Version: ", calculator.Version)
}

Observe que a instrução de importação usa o nome do pacote que você criou: calculator. Para executar uma chamada à função Sum desse pacote, será preciso especificar o nome do pacote, como em calculator.Sum. Por fim, agora você também tem acesso à variável Version. Chame-a desta forma: calculator.Version.

Se você tentar executar o programa agora, ele não funcionará. Você precisa informar ao Go que está usando módulos para fazer referência a outros pacotes. Para fazer isso, execute este comando no diretório $GOPATH/src/helloworld:

go mod init helloworld

No comando anterior, helloworld é o nome do projeto. Esse comando cria um arquivo go.mod. Portanto, agora o diretório de árvore será parecido com este:

src/
  calculator/
    go.mod
    sum.go
  helloworld/
    go.mod
    main.go

Quando você abrir o arquivo go.mod, verá algo semelhante ao código a seguir. (A versão do Go pode ser diferente.)

module helloworld

go 1.14

Como você está referenciando uma cópia local do módulo, informe o Go de que não deseja usar uma localização remota. Portanto, você precisará modificar manualmente o arquivo go.mod para incluir a referência, desta forma:

module helloworld

go 1.14

require github.com/myuser/calculator v0.0.0

replace github.com/myuser/calculator => ../calculator

A palavra-chave replace especifica o uso de um diretório local em vez de uma localização remota para o módulo. Nesse caso, como os programas helloworld e calculator estão em $GOPATH/src, a localização é simplesmente ../calculator. Se a origem do módulo estiver em outra localização, você definirá o caminho local aqui.

Execute o programa usando este comando:

go run main.go

A saída será a seguinte:

8
Version:  1.0

Desafio 1

O que acontecerá se você tentar chamar a variável logMessage ou a função internalSum por meio do pacote calculator no aplicativo principal? Ela será executada? Experimentar!

Solução do desafio:

package main

import (
 "fmt"
 "github.com/myuser/calculator"
)

func main() {
    total := calculator.internalSum(5)
    fmt.Println(total)
    fmt.Println("Version: ", calculator.logMessage)
}

Publicar um pacote

A publicação de um pacote Go é razoavelmente fácil. Você só precisa disponibilizar o código-fonte do pacote publicamente. A maioria dos desenvolvedores usa o GitHub para disponibilizar pacotes para o público, por isso, às vezes você encontrará referências a github.com em instruções de importação.

Por exemplo, caso você deseje publicar seu pacote calculator na sua conta do GitHub, precisará criar um repositório chamado calculator. A URL terá uma aparência semelhante a esta:

https://github.com/myuser/calculator

Você fará o controle de versão dos pacotes marcando o repositório, da seguinte maneira:

git tag v0.1.0
git push origin v0.1.0

Os desenvolvedores que desejam usar seu pacote (incluindo você) referenciarão isso desta forma:

import "github.com/myuser/calculator"

Vamos falar mais detalhadamente sobre como referenciar pacotes de terceiros.

Referenciar pacotes externos (de terceiros)

Às vezes, seus programas precisam referenciar pacotes escritos por outros desenvolvedores. Normalmente, esses pacotes estão disponíveis no GitHub. As instruções a seguir para referenciar pacotes de terceiros funcionam se você está desenvolvendo um pacote (um pacote diferente de main) ou um programa autônomo (o pacote main).

Vamos adicionar uma referência ao pacote rsc.io/quote:

package main

import (
    "fmt"
    "github.com/myuser/calculator"
    "rsc.io/quote"
)

func main() {
    total := calculator.Sum(3, 5)
    fmt.Println(total)
    fmt.Println("Version: ", calculator.Version)
    fmt.Println(quote.Hello())
}

Se você estiver usando o Visual Studio Code, o arquivo go.mod será atualizado quando você o salvar. Agora ele terá esta aparência:

module helloworld

go 1.14

require (
    github.com/myuser/calculator v0.0.0
    rsc.io/quote v1.5.2
)

replace github.com/myuser/calculator => ../calculator

Observe como rsc.io/quote referencia uma versão específica do pacote. Quando precisar atualizar as dependências do seu programa, você precisará alterar a versão aqui.

Execute o programa novamente usando este comando:

go run main.go

O resultado deve ser assim:

8
Version:  1.0
Hello, world.

Todas as referências futuras a pacotes de terceiros precisarão estar no arquivo go.mod. Quando você executar ou compilar o aplicativo, o Go baixará todas as dependências dele.