O Go 1.16, a 17ª versão principal da linguagem de programação Go, acaba de ser lançado. É uma atualização significativa que traz muitos recursos e refinamentos há muito esperados para a linguagem. O modo com reconhecimento de módulo é habilitado por padrão, o suporte a silício da Apple está ativo, a incorporação nativa de ativos estáticos está aqui e os métodos no pacote io/ioutil
foram reorganizados para que agora faça sentido lógico. Neste artigo, daremos uma olhada em alguns dos destaques desta versão.
Suporte nativo para silício Apple
Desde o seu início, Go priorizou a portabilidade entre diferentes sistemas operacionais e arquiteturas e isso se reflete em seu suporte para uma ampla variedade de sistema operacional e combinações de arquitetura .
Nos últimos meses, o lançamento do primeiro ARM Mac de 64 bits da Apple foi um dos tópicos mais dominantes entre os desenvolvedores devido ao seu salto impressionante no desempenho de CPU, GPU e bateria. O projeto Go respondeu prontamente adicionando suporte nativo para ARM Macs por meio das variáveis ambientais GOOS=darwin
e GOARCH=arm64
.
Se você tiver um Mac M1, agora poderá criar e executar programas Go nativamente em seu computador e, se estiver em um sistema operacional diferente ou em um Mac baseado em Intel, pode direcionar Macs ARM por definindo as variáveis ambientais acima ao construir o binário para seu programa:
GOARCH=arm64 GOOS=darwin vá construir meu aplicativo
Incorporação nativa de arquivos estáticos
Uma das melhores coisas sobre Go é que programas compilados podem ser distribuídos e executados como um único arquivo binário livre de dependência. Esta vantagem é um pouco compensada quando um programa depende de arquivos estáticos, como modelos HTML, arquivos de migração de banco de dados, ativos de aplicativos da web como JavaScript ou arquivos de imagens como esses arquivos, muitas vezes precisam ser distribuídos com o binário, a menos que sejam incorporados ao binário a ajuda de um pacote de terceiros, como pkger ou packr . Com o lançamento do Go 1.16, agora é possível incluir nativamente arquivos estáticos em um binário Go por meio do novo pacote embed
.
Este é o exemplo mais básico de como esse recurso funciona. Supondo que você tenha um arquivo sample.txt
cujo conteúdo é mostrado abaixo:
Olá do arquivo de texto
E um arquivo main.go
no mesmo diretório com o seguinte conteúdo:
pacote principal importar ( _"Embutir" "fmt" ) //go: embed sample.txt var string de texto func main () { fmt.Print (texto) }
A diretiva go: embed
colocada acima da variável text
instrui o compilador a incorporar o conteúdo do arquivo sample.txt
como uma string na variável text
. Se você construir o programa com go build
e mover o binário resultante para um local diferente, você notará que executá-lo imprimirá o conteúdo do arquivo embutido na saída padrão. Isso ocorre porque todo o conteúdo do arquivo sample.txt
foi incluído dentro do binário para que possa ser distribuído como está:
$ mv main/tmp $ cd/tmp $./main Olá do arquivo de texto
Para um exemplo mais realista, digamos que temos um projeto de aplicativo da web com a seguinte estrutura de diretório:
. ├── ativos │ ├── css │ │ └── style.css │ └── js │ └── script.js ├── go.mod ├── index.html ├── main.go └── aleatório
Podemos incorporar todos os arquivos na pasta assets
e no arquivo index.html
assim:
pacote principal importar ( "Embutir" "net/http" ) //go: embed assets/* var assets embed.FS //go: embed index.html var html [] byte func main () { fs:=http.FileServer (http.FS (ativos)) http.Handle ("/ativos/", fs) http.HandleFunc ("/", func (w http.ResponseWriter, r * http.Request) { w.Header (). Adicionar ("Content-Type","text/html") w.Write (html) }) http.ListenAndServe (": 8080", nulo) }
O tipo FS
é útil para incorporar uma árvore de arquivos, como um diretório de ativos de servidor da web, como no exemplo acima. Para incorporar um único arquivo como index.html
, uma variável do tipo string
ou [] byte
é melhor. Se você construir e executar o programa e navegar até http://localhost: 8080 , verá o conteúdo do arquivo HTML com os ativos estáticos aplicados corretamente:
versão $ go go versão go1.16rc1 linux/amd64 $ go build-o main $ mv main/tmp $ cd/tmp &&./main
Você pode baixar o conteúdo de index.html , style.css e script.js arquivo se desejar executar o exemplo localmente. Para obter mais detalhes, consulte a documentação para o novo pacote embed.
Algumas pegadinhas
Antes de usar a diretiva //go: embed
, você deve importar o pacote embed
. Caso contrário, você obterá um erro:
$ go run main.go # argumentos da linha de comando ./main.go:8:3://go: embed permitido apenas em arquivos Go que importam"embed"
Se você não estiver usando nenhuma identificação exportada diretamente de embed
, certifique-se de prefixar a instrução de importação com um sublinhado:
import ( _"Embutir" )
Outra coisa a se estar ciente é que //go: embed
funciona apenas em variáveis de nível de pacote. Se você tentar usá-lo dentro de uma função, seu código não compilará:
pacote principal importar ( _"Embutir" "fmt" ) func main () { //vá: embed index.html var string html fmt.Println (html) }
$ go run main.go # argumentos da linha de comando ./main.go:9:4: go: embed não pode ser aplicado a var dentro de func
O modo com reconhecimento de módulo é habilitado por padrão
A introdução dos módulos Go em Go 1.11 anunciou um afastamento da semântica GOPATH
para gerenciamento de dependências. Nessa versão inicial e Go 1.12 , os módulos ainda eram experimentais e tinham que ser ativado com a variável de ambiente GO111MODULE=on
. Go 1.13 garantiu que o modo com reconhecimento de módulo fosse ativado automaticamente sempre que um O arquivo go.mod
está presente no diretório de trabalho atual ou em um diretório pai, mesmo se o diretório estiver dentro do GOPATH
e este permaneceu o caso em Go 1.14 e 1,15 .
Com o lançamento do Go 1.16, a variável GO111MODULE
agora é padronizada como on
, o que significa que o modo com reconhecimento de módulo está habilitado por padrão, independentemente de um go O arquivo.mod
está presente no diretório atual. Se você deseja reverter para o comportamento anterior, defina GO111MODULE
como auto
.
Em outras alterações relacionadas, go build
e go test
não modificarão mais o go.mod
e go.sum
arquivos por padrão. Em vez disso, um erro será relatado se um requisito de módulo ou soma de verificação precisar ser adicionado ou atualizado. Você pode então usar go mod tidy
ou go get
para ajustar os requisitos de acordo.
O comando go install
agora também reconhece o módulo, o que significa que não afetará o arquivo go.mod
no diretório atual ou em qualquer diretório pai, se há um. Além disso, agora ele pode receber um número de versão como sufixo. Por exemplo:
$ go install github.com/[email protected]
No Go 1.16, o uso de go get
para construir e instalar pacotes foi descontinuado em favor de go install
. Em uma versão futura, go get
não será mais capaz de construir e instalar pacotes, mas funcionará como atualmente com o sinalizador -d
habilitado, o que significa que ajustará o atual dependências do módulo sem construir pacotes. O sinalizador -insecure
ou -i
a também foi descontinuado.
Os autores do pacote agora podem retirar versões antigas
A partir do Go 1.16, uma nova diretiva de retração estará disponível nos arquivos go.mod
. Isso permite que os autores dos pacotes marquem as versões mais antigas do pacote como inseguras ou quebradas ou se uma versão foi publicada acidentalmente. Veja como usá-lo:
exemplo do módulo
ir 1,16 retrair v1.1.1//retrair versão única retrair [v1.1.1, v1.3.2]//intervalo fechado, então qualquer coisa entre v1.1.1 e v1.3.2
O pacote io/ioutil
agora está obsoleto
O pacote ioutil
inteiro agora está obsoleto no Go 1.16 e suas funções foram movidas para outros pacotes. Para ser claro, o código existente que utiliza este pacote continuará a funcionar, mas você é incentivado a migrar para as novas definições nos pacotes io
e os
.
A migração de código usando ioutil
deve ser direta. Um método popular neste pacote é o método ReadAll ()
, que geralmente é usado para ler todo o corpo de resposta de uma solicitação HTTP em uma fatia de bytes. Este método foi movido para o pacote io
:
resp, err:=http.Get (url) se errar!=nulo { return err } adiar resp.Body.Close () //maneira antiga: corpo, erro:=ioutil.ReadAll (resp.Body) corpo, errar:=io.ReadAll (resp.Body) se errar!=nulo { return err }
A lista completa dos novos locais dos métodos io/ioutil
exportados é mostrada abaixo:
- ioutil.Discard => io.Discard
- ioutil.NopCloser => io.NopCloser
- ioutil.ReadAll => io.ReadAll
- ioutil.ReadDir => os.ReadDir (retorna uma fatia de
os.DirEntry
em vez de uma fatia defs.FileInfo
) - ioutil.ReadFile => os.ReadFile
- ioutil.TempDir => os.MkdirTemp
- ioutil.TempFile => os.CreateTemp
- ioutil.WriteFile => os.WriteFile
O pacote io/fs
As melhorias na biblioteca padrão Go não foram deixadas de fora nesta versão com a adição dos pacotes io/fs
e testing/testfs
. Esses novos pacotes tornam mais fácil abstrair um sistema de arquivos em testes, o que os torna mais facilmente reproduzíveis, independentemente do sistema operacional em que estão sendo executados. O acesso aos arquivos também será muito mais rápido e você não terá que limpar os arquivos temporários depois.
Antes do Go 1.16, a tarefa de simular um sistema de arquivos frequentemente recaía sobre o popular afero pacote que fornece um tipo de interface que deve esteja satisfeito em implementar um sistema de arquivos real ou simulado. Ele também fornece algumas implementações comuns que fornecem essa interface, como afero. MemMapFs , que é um sistema de arquivos de memória útil para simulação em testes.
Ao contrário da interface Fs do afero que define 13 métodos no momento da escrita, a interface FS fornecida pelo pacote io/fs
é bastante simples:
interface de
tipo FS { Abrir (string de nome) (arquivo, erro) }
Tudo que você precisa fazer para implementar esta interface é um método Open
que pode abrir um arquivo em um caminho e retornar um objeto que implementa a interface fs.File
que é mostrado abaixo:
type File interface { Stat () (FileInfo, erro) Ler ([] byte) (int, erro) Fechar () erro }
Uma coisa que você notará na interface acima é a falta de métodos que permitem a modificação de arquivos. Isso porque o pacote io/fs
fornece apenas uma interface somente leitura para sistemas de arquivos, ao contrário do Afero, que é mais completo nesse aspecto. O motivo para esta decisão é que a leitura é mais fácil para resumir em comparação com a escrita, que é mais envolvente.
Tudo isso é para dizer que acho que a decisão de design de limitar esta proposta para operações somente leitura é uma boa. Na verdade, foi o insight principal (por @robpike) que desbloqueou anos de estagnação e nos permitiu fazer qualquer progresso na definição dessa interface.
Menções notáveis
A ferramenta vet agora fornece um aviso quando uma chamada inválida para testing.T
ou testing.B
de Fatal
, Os métodos Fatalf
ou FailNow
são feitos de dentro de uma goroutine criada durante um teste ou benchmark. Isso ocorre porque esses métodos saem do goroutine em vez da função de teste ou benchmark:
pacote principal importar"teste" função TestFoo (t * testing.T) { go func () { se for verdade { t.Fatal ("Teste falhou")//sai do goroutine em vez de TestFoo } } () }
As chamadas para os métodos acima podem ser substituídas por t.Error ()
para sinalizar a falha do teste e uma instrução return
para sair do goroutine:
pacote principal importar"teste" função TestFoo (t * testing.T) { go func () { se for verdade { t.Error ("Teste falhou.") Retorna } } () }
Houve também várias pequenas atualizações e correções para pacotes de biblioteca padrão. A lista completa de alterações pode ser encontrada nas notas de versão .
Conclusão
Se você quiser explorar a lista completa de correções de bugs e recursos incluídos nesta versão, encorajo você a verificar a lista de problemas encerrados em Go 1.16 milestone no GitHub.
Obrigado por ler e feliz programação!
A postagem O que há de novo no Go 1.16 apareceu primeiro em LogRocket Blog .