Criando aplicações com GoLang

Criando aplicações com GoLang

Agora que você já foi introduzido a linguagem Go, e já possui todos os arquivos necessários para rodá-lo na sua máquina local.

Chegou a hora de criarmos o nosso primeiro programa em GoLang 😄

Digo... durante a lição de configuração de ambiente, eu já tinha criado um leve programinha capaz de executar um Hello World, você se lembra?

Além disso, eu te instruí a criar uma pasta chamada JornadGoLang dentro da sua área de trabalho, pois é lá que iremos armazenar todos os projetos que estamos fazendo durante esta jornada.

Feito isso, que tal explorar algumas convenções em Go? 😉

Convenções em Go

Quando criamos o nosso primeiro projeto em Go, a própria documentação nos instruí sobre o fato de que devemos seguir algumas convenções.

A primeira delas, e uma das mais importantes, é que dentro de um projeto (pasta) em Go, você pode ter múltiplos arquivos *.go, como por exemplo:

Supondo que você tenha criado uma pasta chamada Calculadora, que representa o seu projeto em Go, dentro dela, você pode ter diversos arquivos que utilizam a extensão .go, como:

  • main.go
  • somas.go
  • divisao.go
  • resultados.go
  • e entre outros...

Entretanto, o Go exige que o arquivo executável principal da sua aplicação (geralmente chamada de main.go), pertença ao pacote main, e contenha uma única função chamada main().

Além disso, se houver mais de um arquivo no mesmo diretório com package main, o Go os compilará juntos, desde que apenas um deles tenha a declaração func main().

Para exemplificar tudo isso que foi dito acima, dentro da pasta JornadaGoLang nós iremos criar uma subpasta chamada de 2-convencoes-em-go:

Dentro dela, vamos criar um novo arquivo chamado de main.go.

Esse arquivo, será o arquivo principal da nossa aplicação, e é nele que iremos executar toda a lógica do nosso projeto.

Obrigatoriamente, como ele é o ponto principal da nossa aplicação, nós devemos importar o pacote main dentro daquele arquivo que acabamos de criar, sendo assim, abra o main.go, e digite o seguinte comando na primeira linha:

package main

O package main em Go é um pacote especial usado para indicar que um arquivo pertence a um programa executável. Ele define o ponto de entrada do programa e precisa conter a função func main(), que é onde a execução começa.

E como dito anteriormente, se ele é o ponto principal da nossa aplicação, ele precisa precisa conter uma função chamada main(), e é certo que o nosso main.go, fique agora da seguinte forma:

package main

func main() {
    //Aqui você coloca a lógica inteira da sua aplicação...
}

O main() nada mais é do que uma função que é chamada pelo compilador quando o usuário (ou você) executa o seu programa. Como descrito no comentário acima, é ali dentro que você colocará toda a lógica do seu código (ou faz chamadas a outras funções).

É claro que se você executar no terminal (dentro da pasta do projeto) o seguinte comando abaixo:

go run main.go

O terminal não irá retornar nada, uma vez que não criamos nenhuma lógica dentro da função main().

Para que este exemplo não fique tão cru, vamos adicionar uma mensagem de texto usando a biblioteca fmt, e para isso você vai precisar importá-la fora do main(), da seguinte forma:

package main

import "fmt"

func main() {
    fmt.Println("Olá, mundo!")
}

O método Println da biblioteca fmt, é responsável por mostrar uma mensagem personalizada no console.

Se você executar o comando run do go, verá que uma mensagem de boas vindas acaba de ser gerada no terminal:

Olá, mundo!

Feito isso, vamos começar a testar algumas outras coisas 😉

Múltiplos arquivos com package main

Sim, no Go você pode dividir seu código em vários outros arquivos no mesmo diretório, desde que o arquivo principal (main.go) tenha a função main(), pois dessa forma o Go entenderá que esse será o ponto de entrada da aplicação.

Para exemplificar isso, vamos criar mais dois arquivos, um chamado de utils.go e outro chamado de handlers.go dentro da pasta do nosso projeto.

utils.go:

package main

import "fmt"

func SayUtils() {
    fmt.Printf("Olá utils...")
}

handlers.go:

package main

import "fmt"

func HandleRequest() { // Nome corrigido: começa com maiúscula
    fmt.Println("Estes são os handlers...")
}

Perceba que nenhum dos arquivos auxiliares (utils.go e handlers.go) conta com uma função main(), mas todos pertencem ao mesmo package main.

Sendo assim, se você executar o comando:

go run .

Ou como estamos acostumados:

go run main.go

O Go automaticamente compilará todos os arquivos do diretório que pertencem ao package main.

Como eles ainda não se relacionam, é bem provável que a saída será apenas uma mensagem de boas vindas do main.go:

Olá, mundo!

Mas você poderia simplesmente alterar o seu main.go, para chamar as duas funções que existem nos outros dois arquivos que criamos, por exemplo:

main.go:

package main

import "fmt"

func main() {
    fmt.Println("Olá, mundo") 
    HandleRequest()
    SayUtils()
}

Agora para que o Go compile o main.go em conjunto com todos os arquivos existente no diretório, você pode fazer isso de duas formas:

go run .

Ou, caso preferir:

go run main.go handlers.go utils.go

Veja como ficou o resultado final no terminal:

Observação: se você executar o comando go run main.go, um código de erro será retornado alegando de que tais funções (HandleRequest e SayUtils) não foram encontradas. Isso ocorre porque você está rodando um único arquivo, que no caso é o main.go, em vez de todos os outros que estão rodando naquela pasta.

Mas o que aconteceria, se também existisse uma função chamada main() dentro dos arquivos handlers.go e utils.go, e tentássemos compilar o projeto?

handlers.go:

package main

import "fmt"

func HandleRequest() {
    fmt.Println("Estes são os handlers...")
}

func main() {
    fmt.Println("Olá, mundo") 
}

utils.go:

package main

import "fmt"

func SayUtils() {
    fmt.Printf("Olá utils...")
}

func main() {
    fmt.Println("Olá, mundo") 
}

Para testar essa ideia, tente executar:

go run main.go handlers.go utils.go

Olha só o que apareceu no terminal:

Uma mensagem confirmando de que NÃO PODEMOS TER MAIS DE UMA FUNÇÃO MAIN em outros arquivos.

O que vai ao encontro daquilo que comentei logo no início desta lição 😉

Subpastas e módulos

Quando estamos criando nossas aplicações em Go, é comum organizarmos a lógica do nosso código dentro de subpastas, como por exemplo:

myproject/
├── main.go            (package main)
├── services/
│   ├── user.go        (package services)
│   ├── order.go       (package services)
├── utils/
│   ├── helpers.go     (package utils)

A organização acima está setada de forma modular, e faz parte de um dos princípios da arquitetura de software.

Subpastas geralmente não pertencem ao package main, mas a pacotes reutilizáveis, que no caso do nosso exemplo acima, foram representados pelas subpastas services e utils.

E como dito anteriormente, dentro do seu main.go, você pode importar todas essas subpastas, usando o comando import:

package main

import (
    "myproject/services"
    "myproject/utils"
)

func main() {
    services.DoSomething()
    utils.HelperFunction()
}

Observação: fique tranquilo que teremos uma lição exclusiva para falar sobre módulos e importações.

Sendo assim, podemos concluir que:

  • Pode haver vários arquivos *.go dentro da pasta do projeto.
  • Pode haver múltiplos arquivos com package main no mesmo diretório, mas só um deles deve ter func main().
  • Subpastas podem conter outros pacotes, mas não devem ter main.go, a menos que você queira múltiplos binários.

E falando em binários, você sabia que é possível gerar um executável via linha de comando com GoLang?

Não? Então vamos aprender como fazer isso agora 😉

🔥Go Run VS Go Build

O Go oferece dois comandos principais para executar e compilar programas, são os famosos go run e go build.

No caso do go run, ele compila e executa o código de forma temporária, sem gerar um arquivo executável permanente. Neste caso, por de baixo dos panos, o Go gera um executável que será salvo na memória do computador e o executa na hora.

go run main.go

O go run, é ideal para testar rapidamente a sua aplicação sem a necessidade de precisar gerar um arquivo, para posteriormente executar este arquivo.

Já o go build, ele compila o código e gera um executável binário dentro do diretório de onde ele foi chamado. Tal executável pode ser rodado posteriormente sem a necessidade de ter os arquivos de instalação do Go na sua máquina local, ou na máquina do seu usuário.

go build main.go

É importante ressaltar que o nome do arquivo gerado depende do seu sistema operacional:

  • Linux e macOS: ./main
  • Windows: main.exe

Após a compilação e geração deste executável, basta executar no seu terminal um dos comandos abaixo:

./main  # Linux/macOS
main.exe  # Windows

Se quiser compilar um projeto inteiro, basta usar o go build dessa forma:

go build .

Entretanto, você pode estar se fazendo as seguintes perguntas:

  • Como esses executáveis são gerados?
  • Em qual arquitetura tais executáveis são gerados?

Responderemos cada uma delas a diante 😉

📌 Como o Go gera tais executáveis?

O Go gera executáveis nativos que não precisam de uma VM (Virtual Machine) ou runtime separado para rodar, pois todo o código e dependências são compilados para um único binário.

Isso faz com que os executáveis sejam rápidos e portáteis, sem dependências externas.

🎯Em qual arquitetura tais executáveis são gerados?

Por padrão, o Go gera executáveis compatíveis com a arquitetura do seu sistema operacional.

Isso significa que se você instalou o Go em uma máquina de 32Bits, os binários terão suporte para rodar apenas em máquinas 32Bits.

Se você instalou o Go em uma máquina de 64Bits, os binários terão suporte apenas para máquinas 64Bits.

Para descobrir a sua arquitetura atual, você pode consultar as variáveis de ambiente do Go, mais especificamente uma chamada de GOARCH:

go env GOOS GOARCH

Dependendo da arquitetura do seu computador, ele pode retornar alguns resultados diferentes:

windows amd64
...
linux arm64

Entretanto, o Go permite que você possa compilar seus binários para outros plataformas além da sua atual.

Para isso, você só precisa mudar as configurações da sua variável de ambiente, vamos ver alguns exemplos...

🖥️ Gerar um executável para Windows 64 bits:

GOOS=windows GOARCH=amd64 go build -o meu_programa.exe

🍏 Gerar um executável para macOS ARM (Apple Silicon M1/M2/M3):

GOOS=darwin GOARCH=arm64 go build -o meu_programa

🐧 Gerar um executável para Linux ARM64 (exemplo: Raspberry Pi):

GOOS=linux GOARCH=arm64 go build -o meu_programa

Abaixo, você vai encontrar as principais arquiteturas suportadas pelo GoLang:

👾 amd64 (64 bits (x86_64)): PCs modernos (Windows, Linux, Mac).

👾 386 (32 Bits (X86)): PCs antigos, Windows 32 bits.

👾 arm64 (ARM 64 Bits): Apple M1/M2, Raspberry Pi, celulares.

👾 arm (ARM 32 Bits): Dispositivos IoT, Android antigos.

Portanto, podemos resumir que:

go run = Executa temporariamente, sem gerar um binário fixo.

go build = Gera um executável nativo e independente.

✅ O Go compila direto para as arquiteturas x64, ARM64, Windows, Linux, macOS e muito mais!

✅ Pode gerar binários para outras plataformas usando GOOS e GOARCH.

Repositório da lição

Todos os arquivos relacionados com esta lição, podem ser encontrados nos seguintes repositórios abaixo:

Conclusão

Nesta lição, você aprendeu algumas convenções gerais da linguagem Go e aprendeu a gerar binários com o comando go build.

Na próxima lição, aprenderemos um pouco mais sobre como fazer comentários em nossos códigos.

Te aguardo lá 😯

Criadores de Conteúdo

Foto do William Lima
William Lima
Fundador da Micilini

Inventor nato, escreve conteudos de programação para o portal da micilini.

Torne-se um MIC 🤖

Mais de 100 mic's já estão conectados na plataforma.