Índice do curso
Lição 2 — Variáveis, funções e tipos
Por Dorian Chávez · fundador da Hábil e arquiteto de integração ·
Duração: 90 minutos, ou duas sessões de 45.
Ao terminar, você vai conseguir:
- Explicar o que o compilador de Go faz com o seu arquivo de texto.
- Declarar variáveis e saber quando usar
:=e quando=. - Citar os quatro tipos básicos e dizer por que Go não deixa você misturá-los.
- Escrever funções que recebem e devolvem valores.
- Entender por que uma função de Go pode retornar duas coisas ao mesmo tempo.
- Ler as mensagens de erro do compilador e saber o que ele está pedindo.
- Escrever, compilar e executar um programa completo por conta própria.
Por que isso importa
O revisor —o programa que você vai construir durante todo o curso— precisa, desde a sua primeira
linha, de três coisas: dados (o nome de um serviço, sua porta, quanto demorou para responder),
lógica que decida algo com esses dados (está rápido ou lento?) e uma forma de avisar quando algo
deu errado (o serviço não respondeu?). Isso é, nessa ordem, exatamente o que esta lição ensina:
variáveis para guardar dados, funções para a lógica, e o padrão de dois valores de retorno para os erros.
Não é por acaso que Go é compilado e de tipagem estática: as duas decisões existem para que o
computador pegue seus erros antes de o programa rodar, em vez de um usuário descobri-los em
produção. Uma linguagem interpretada deixa você escrever puerto = "muchos" e só estoura quando essa
linha é executada —o que pode ser dez minutos depois, ou nunca, se esse trecho do código quase não é
usado—. Go se recusa a produzir o executável. Essa diferença é a razão de fundo de quase tudo o que você
vai ver nesta lição: por que o compilador é estrito, por que existe o «valor zero», e por que uma função
que pode falhar tem de dizê-lo na sua assinatura, e não como uma surpresa.
No final da lição você vai escrever o primeiro passo real do revisor (exercício de projeto): uma
função que recebe o nome de um serviço, sua porta e seu tempo de resposta, e devolve uma linha de
relatório classificada. Ainda sem structs, sem concorrência e sem HTTP —isso vem depois— mas já é um
código que se parece com o programa final.
Os conceitos
2.1 O que o compilador faz
Você escreve um arquivo de texto. Esse arquivo, por si só, não faz nada: é texto. Para que o computador o execute, algo tem de traduzi-lo para as instruções que o processador entende.
Há duas maneiras de fazer essa tradução:
| Como funciona | Linguagens | |
|---|---|---|
| Interpretada | Um programa lê o seu texto linha por linha e faz o que ele diz, cada vez que você o executa | Python, JavaScript, PHP |
| Compilada | Um programa traduz todo o seu texto uma única vez e guarda o resultado em um arquivo executável | Go, C, C++, Rust |
Go é compilado, e isso tem três consequências que você vai notar desde hoje:
- Há uma etapa antes de executar: compilar. Se você escreveu errado o nome de uma variável, descobre ali — antes de o programa rodar. Em uma linguagem interpretada você descobriria quando a execução chegasse a essa linha, o que pode ser dez minutos depois ou nunca.
- O resultado é um arquivo que funciona sozinho. Não precisa que o outro computador tenha Go instalado.
- É rápido para executar, porque a tradução já está feita.
2.2 Seu primeiro programa, linha por linha
Vamos escrever, compilar e executar um programa completo. Todos os programas deste curso são completos e executáveis: nada de fragmentos que não podem ser rodados.
Prepare a pasta:
mkdir -p ~/w/curso-go/cap01 && cd ~/w/curso-go/cap01
go mod init cap01
Fig. 2.1 | Um programa que imprime uma mensagem.
1 // fig02_01.go
2 // Imprime un mensaje en la pantalla.
3 package main
4
5 import "fmt"
6
7 func main() {
8 fmt.Println("Bienvenido a Go!")
9 }
Compile-o e execute-o:
$ go run fig02_01.go
Bienvenido a Go!
Agora cada linha, porque todas têm uma razão:
Linhas 1-2. Comentários. Começam com // e o compilador os ignora por completo. Estão ali para quem
ler o código — incluindo você daqui a três semanas.
Linha 3: package main. Todo arquivo de Go pertence a um pacote, que é um agrupamento de código.
O pacote main é especial: é o único que produz um programa executável. Se você escrevesse
package utilidades, teria uma biblioteca que outros programas podem usar, mas que não pode ser
executada sozinha.
Linha 5: import "fmt". Diz ao compilador que você vai usar código do pacote fmt (de format),
que vem com Go e contém as funções para imprimir e formatar texto. Go não carrega nada por padrão:
tudo o que você usar, você pede.
Linha 7: func main() {. Declara a função main, que é onde começa a execução do programa.
Quando você executa um programa Go, o sistema procura exatamente esta função. Se você a chamasse de
principal ou inicio, o programa não iniciaria.
Linha 8: fmt.Println("Bienvenido a Go!"). Chama a função Println que está dentro do pacote
fmt. O ponto se lê como «de»: «a função Println de fmt». Println imprime o que você der a
ela e pula para a linha seguinte (print line).
Linha 9: }. Fecha o corpo da função. Em Go as chaves delimitam blocos, como em C, C++, Java ou
JavaScript.
2.2.1 A diferença entre go run e go build
Fig. 2.2 | As duas formas de executar o seu programa.
$ go run fig02_01.go # compila en memoria, ejecuta, y no deja archivo
Bienvenido a Go!
$ go build fig02_01.go # compila y GUARDA el ejecutable
$ ls -la
-rwxr-xr-x 1 usuario usuario 1841624 fig02_01 ← el programa
-rw-r--r-- 1 usuario usuario 104 fig02_01.go ← tu texto
$ ./fig02_01 # y se ejecuta directo
Bienvenido a Go!
Repare nos tamanhos: o seu texto tem 104 bytes; o programa compilado, 1,8 megabyte. A diferença é que o executável traz dentro tudo o que precisa para funcionar.
2.3 Variáveis
Uma variável é um espaço de memória com um nome, onde você guarda um dado que o seu programa vai usar.
Fig. 2.3 | Declarar variáveis e imprimi-las.
1 // fig02_03.go
2 // Declara variables de distintos tipos y las imprime.
3 package main
4
5 import "fmt"
6
7 func main() {
8 nombre := "catalogo" // texto
9 puerto := 443 // número entero
10 tiempo := 0.142 // número con decimales
11 seguro := true // verdadero o falso
12
13 fmt.Println("servicio:", nombre)
14 fmt.Println("puerto:", puerto)
15 fmt.Println("tiempo de respuesta:", tiempo)
16 fmt.Println("usa HTTPS:", seguro)
17 }
$ go run fig02_03.go
servicio: catalogo
puerto: 443
tiempo de respuesta: 0.142
usa HTTPS: true
O operador := se lê «declare uma variável nova e guarde isto nela». Go olha o valor da direita
e deduz o tipo sozinho: "catalogo" está entre aspas, então é texto; 443 não as tem e não tem
ponto, então é inteiro.
2.3.1 := contra =
Quando a variável já existe, para mudar o valor dela você usa = sem os dois-pontos:
Fig. 2.4 | Criar e modificar uma variável.
1 // fig02_04.go
2 package main
3
4 import "fmt"
5
6 func main() {
7 puerto := 443 // la CREA con valor 443
8 fmt.Println(puerto)
9
10 puerto = 8080 // le CAMBIA el valor
11 fmt.Println(puerto)
12 }
$ go run fig02_04.go
443
8080
2.3.2 Go se recusa a compilar se você não usa uma variável
Fig. 2.5 | Um programa que não compila, de propósito.
1 // fig02_05.go — este programa NO compila
2 package main
3
4 import "fmt"
5
6 func main() {
7 nombre := "catalogo"
8 edad := 30 // se declara y nunca se usa
9 fmt.Println(nombre)
10 }
$ go run fig02_05.go
# command-line-arguments
./fig02_05.go:8:5: declared and not used: edad
Go não permite. Não é um aviso que você possa ignorar: é um erro que interrompe a compilação.
Por que tão estrito? Porque uma variável que não é usada quase sempre significa uma de duas coisas: você errou ao escrever o nome em outra linha, ou sobrou lixo de um código que você apagou pela metade. As duas são problemas. Go prefere te incomodar hoje a deixar código morto se acumulando para sempre.
2.4 Os tipos básicos
Um tipo é a resposta à pergunta «que tipo de dado é este?». Os quatro que você vai usar o tempo todo:
| Tipo | O que guarda | Exemplos | Valor zero |
|---|---|---|---|
string |
texto | "hola", "https://catalogo.example.com" |
"" (vazio) |
int |
números inteiros | 42, -7, 0 |
0 |
float64 |
números com casas decimais | 3.14, 0.142 |
0 |
bool |
verdadeiro ou falso | true, false |
false |
2.4.1 Go não mistura tipos
Fig. 2.6 | Outro programa que não compila, de propósito.
1 // fig02_06.go — este programa NO compila
2 package main
3
4 import "fmt"
5
6 func main() {
7 puerto := 443
8 puerto = "muchos" // intenta guardar texto en un entero
9 fmt.Println(puerto)
10 }
$ go run fig02_06.go
# command-line-arguments
./fig02_06.go:8:14: cannot use "muchos" (untyped string constant) as int value in assignment
Em Python isto funcionaria sem reclamação. Em Go não compila, e isso é uma vantagem enorme:
2.4.2 O valor zero: em Go nunca há lixo
Fig. 2.7 | Variáveis declaradas sem valor.
1 // fig02_07.go
2 // Muestra el valor cero de cada tipo basico.
3 package main
4
5 import "fmt"
6
7 func main() {
8 var texto string
9 var entero int
10 var decimal float64
11 var logico bool
12
13 fmt.Printf("string: %q\n", texto)
14 fmt.Printf("int: %d\n", entero)
15 fmt.Printf("float64: %v\n", decimal)
16 fmt.Printf("bool: %t\n", logico)
17 }
$ go run fig02_07.go
string: ""
int: 0
float64: 0
bool: false
A forma var nombre tipo declara uma variável sem dar valor a ela. Em outras linguagens isso
deixaria «lixo» —o que houvesse naquela memória— ou um estado especial de «indefinido». Em Go ela
sempre recebe um valor válido, chamado valor zero.
E aqui aparece o Printf, que é diferente do Println: recebe um modelo com lacunas e vai
preenchendo-as. Cada lacuna começa com %:
| Para quê | |
|---|---|
%d |
um número inteiro (decimal) |
%s |
texto (string) |
%q |
texto com aspas (quoted) — útil para ver se algo está vazio |
%t |
um bool (true/false) |
%v |
qualquer coisa, no seu formato natural (value) |
\n |
quebra de linha (Printf não pula sozinho, Println sim) |
2.5 Funções
Uma função é um bloco de código com nome, ao qual você pode dar dados e que pode devolver um
resultado. Você já usou duas: fmt.Println e fmt.Printf.
Fig. 2.8 | Definir e chamar funções.
1 // fig02_08.go
2 // Define funciones que reciben y devuelven valores.
3 package main
4
5 import "fmt"
6
7 // sumar recibe dos enteros y devuelve su suma.
8 func sumar(a int, b int) int {
9 return a + b
10 }
11
12 // etiqueta arma un texto descriptivo del servicio.
13 func etiqueta(nombre string, puerto int) string {
14 return fmt.Sprintf("%s:%d", nombre, puerto)
15 }
16
17 // esSeguro dice si el puerto corresponde a HTTPS.
18 func esSeguro(puerto int) bool {
19 return puerto == 443
20 }
21
22 func main() {
23 fmt.Println("2 + 3 =", sumar(2, 3))
24 fmt.Println(etiqueta("catalogo", 443))
25 fmt.Println("catalogo es seguro:", esSeguro(443))
26 fmt.Println("local es seguro:", esSeguro(8080))
27 }
$ go run fig02_08.go
2 + 3 = 5
catalogo:443
catalogo es seguro: true
local es seguro: false
Anatomia da linha 8, que é onde está tudo:
func sumar (a int, b int) int {
│ │ │ │
│ │ │ └── lo que DEVUELVE
│ │ └── lo que RECIBE (los parámetros), con su tipo
│ └── el nombre
└── palabra clave: «voy a definir una función»
Linha 14: fmt.Sprintf. É como o Printf, mas em vez de imprimir, devolve o texto montado. O
S é de string. É usado muitíssimo.
Linha 19: puerto == 443. O igual duplo compara e dá true ou false. Um único igual =
atribui. Confundi-los é clássico (veja «O que se faz errado», mais abaixo).
2.6 Devolver dois valores: a assinatura de Go
Isto é o mais distintivo de Go, e você vai escrevê-lo milhares de vezes na sua carreira. Preste atenção.
Pense em uma função que divide dois números. O que ela faz se o divisor for zero? Não pode devolver um número, porque o resultado não existe.
Outras linguagens usam exceções: a função «lança» um erro e alguém mais acima o «captura» com
try / catch. O problema é que não é óbvio quem o captura nem onde, e é facílimo que ninguém o
faça e o programa morra.
Go faz outra coisa: devolve dois valores. O resultado, e um erro.
Fig. 2.9 | Uma função que devolve um resultado e um possível erro.
1 // fig02_09.go
2 // Devuelve dos valores: el resultado y un posible error.
3 package main
4
5 import (
6 "errors"
7 "fmt"
8 )
9
10 // dividir devuelve el cociente y un error si el divisor es cero.
11 func dividir(a int, b int) (int, error) {
12 if b == 0 {
13 return 0, errors.New("division entre cero")
14 }
15 return a / b, nil
16 }
17
18 func main() {
19 // caso que funciona
20 resultado, err := dividir(10, 2)
21 if err != nil {
22 fmt.Println("error:", err)
23 } else {
24 fmt.Println("10 / 2 =", resultado)
25 }
26
27 // caso que falla
28 resultado, err = dividir(10, 0)
29 if err != nil {
30 fmt.Println("error:", err)
31 } else {
32 fmt.Println("10 / 0 =", resultado)
33 }
34 }
$ go run fig02_09.go
10 / 2 = 5
error: division entre cero
Linha 11: (int, error). Os parênteses com dois tipos significam «esta função devolve duas
coisas»: um inteiro e um erro.
Linha 13: return 0, errors.New(...). Quando há problema, devolve um valor qualquer (aqui 0, que não
vai ser usado) e um erro descrevendo o que aconteceu.
Linha 15: return a / b, nil. Quando tudo vai bem, devolve o resultado e nil.
🔑 nil significa «nada», «vazio», «não há». Então a pergunta if err != nil se lê:
«o erro é diferente de nada?», ou em português normal: «houve erro?»
Linhas 20-21: o padrão que define Go.
resultado, err := dividir(10, 2)
if err != nil {
// algo salió mal: aquí se atiende
}
// si llegaste aquí, todo bien
Esse padrão if err != nil é a linha mais escrita em toda a história de Go. Aparece por toda parte, e
há gente que o critica por ser repetitivo.
2.7 Juntando tudo
Fig. 2.10 | Programa completo que usa tudo o que há na lição.
1 // fig02_10.go
2 // Clasifica servicios por su tiempo de respuesta.
3 package main
4
5 import "fmt"
6
7 // clasificar traduce milisegundos a una etiqueta legible.
8 func clasificar(ms int) string {
9 if ms < 0 {
10 return "sin medir"
11 } else if ms < 500 {
12 return "rapido"
13 } else if ms < 3000 {
14 return "lento"
15 }
16 return "muy lento"
17 }
18
19 // reporte arma una linea del informe.
20 func reporte(nombre string, puerto int, ms int) string {
21 return fmt.Sprintf("%-10s :%-5d %6dms %s",
22 nombre, puerto, ms, clasificar(ms))
23 }
24
25 func main() {
26 fmt.Println("SERVICIO PUERTO TIEMPO ESTADO")
27 fmt.Println("-------------------------------------")
28 fmt.Println(reporte("catalogo", 443, 142))
29 fmt.Println(reporte("pagos", 443, 87))
30 fmt.Println(reporte("inventario", 443, 2310))
31 fmt.Println(reporte("reportes", 3001, 4500))
32 fmt.Println(reporte("viejo", 8080, -1))
33 }
$ go run fig02_10.go
SERVICIO PUERTO TIEMPO ESTADO
-------------------------------------
catalogo :443 142ms rapido
pagos :443 87ms rapido
inventario :443 2310ms lento
reportes :3001 4500ms muy lento
viejo :8080 -1ms sin medir
Este programa já é o antepassado direto do revisor: clasificar e reporte são, em miniatura, o que
na lição 3 vai se converter em um método sobre um struct Servicio, e na lição 6 vai rodar para
vários serviços ao mesmo tempo.
Linha 21: %-10s e %-5d. O número diz quantos espaços de largura reservar, e o sinal de menos
significa alinhado à esquerda. Assim as colunas ficam retas. Sem isso, a tabela sairia torta.
O erro que você vai ver
Quase todas as mensagens de erro de Go têm a mesma forma:
<archivo>:<línea>:<columna>: <qué esperaba el compilador y qué encontró>
Aprender a ler essa linha é metade do trabalho. Dois exemplos que você já viu nesta lição:
./fig02_05.go:8:5: declared and not used: edad
Lê-se: «no arquivo fig02_05.go, linha 8, coluna 5, você declarou edad e nunca a usou». A
correção é simples: ou você usa a variável, ou a apaga, ou —se você realmente a precisa declarada mas
ainda não a usa— a troca pelo identificador em branco _.
./fig02_06.go:8:14: cannot use "muchos" (untyped string constant) as int value in assignment
Lê-se: «na linha 8, coluna 12, você tentou usar o texto "muchos" onde se esperava um int, e eu não
deixo». A correção também não é fácil de adivinhar se você nunca a viu: não existe uma conversão
automática entre string e int em uma atribuição assim. Você teria de converter explicitamente (com
strconv, que veremos mais adiante) ou, mais provável, perceber que misturou o tipo por engano.
E um terceiro, o mais comum da primeira semana, que aparece se você reusa := sobre uma variável que já
existe:
./fig02_04.go:10:9: no new variables on left side of :=
Lê-se: «do lado esquerdo do := não há nenhuma variável nova» — todas já existiam, então Go não sabe
o que declarar. A correção: use = em vez de := quando você já declarou a variável antes.
A regra geral: o compilador de Go quase nunca diz «algo deu errado» em abstrato. Diz o arquivo, a linha, a coluna e uma frase que —ainda que soe estranha da primeira vez— descreve exatamente o problema. Lê-la completa, sem se assustar, resolve a maioria dos casos sem precisar pesquisar nada na internet.
O que se faz errado
- Escrever
printlnem minúscula em vez dePrintln. Go diferencia maiúsculas de minúsculas:Printlneprintlnsão nomes diferentes (printlné uma função interna do compilador, pensada para depurar o próprio Go, não o seu programa). O erro éundefined: fmt.println. - Usar
import "fmt"e não usá-lo, ou usarfmt.Printlnsem oimport. O primeiro dá"fmt" imported and not used; o segundo,undefined: fmt. Os dois são o mesmo tipo de erro: você disse ao compilador algo que não coincide com o que fez. - Confundir
=(atribuir) com==(comparar) dentro de umif. Em C isso compilaria e faria algo inesperado (atribuir o valor e seguir em frente). Em Go é um erro de compilação —cannot use puerto = 443 (...) as value—, o que é uma boa notícia: te barra antes que o programa faça algo que você não pediu. - Esquecer o
\nnoPrintf. O programa compila e roda, mas tudo sai grudado em uma única linha.Printlnpula de linha automaticamente;Printfnão. É um erro silencioso, não um que o compilador aponte. - Ignorar o erro com
_, assim:resultado, _ := dividir(10, 0). Isto também compila, e o programa segue em frente comresultadovalendo0como se tudo estivesse bem. É a forma mais rápida de criar um erro impossível de encontrar depois, porque não há nenhuma mensagem nem queda: o programa simplesmente segue com um dado incorreto. Se alguma vez você descartar um erro com_, que seja uma decisão consciente e comentada, nunca um reflexo para que o compilador pare de reclamar.
Exercícios
Perguntas de revisão
Responda sem ver as respostas. Elas estão no final desta seção.
2.1 Qual é a diferença entre uma linguagem compilada e uma interpretada, e qual das duas é Go?
2.2 Por que a função onde o programa começa tem de se chamar exatamente main?
2.3 Que diferença há entre := e =?
2.4 Que erro Go dá se você declara uma variável e não a usa? Por que você acha que ele faz isso?
2.5 O que é o valor zero e qual é o de string, int e bool?
2.6 O que este programa imprime?
package main
import "fmt"
func main() {
var n int
var s string
fmt.Printf("[%d] [%q]\n", n, s)
}
2.7 Que diferença há entre Println, Printf e Sprintf?
2.8 O que significa nil e o que se pergunta com if err != nil?
2.9 Este programa tem três erros que impedem que compile. Encontre-os sem rodá-lo.
package main
func main() {
nombre := "catalogo"
puerto := 443
puerto := 8080
fmt.Println(nombre)
}
Respostas
2.1 Uma linguagem interpretada é traduzida linha por linha a cada execução; uma compilada é traduzida por completo uma única vez e produz um executável. Go é compilado.
2.2 Porque é uma convenção da linguagem: ao executar um programa, Go procura a função main do
pacote main para começar. Com outro nome ele não encontra por onde iniciar.
2.3 := declara uma variável nova e atribui valor a ela; = apenas atribui a uma que já
existe.
2.4 declared and not used. Faz isso porque uma variável sem uso quase sempre indica um erro —um
nome escrito errado ou restos de código apagado— e Go prefere te barrar a deixar código morto.
2.5 É o valor que uma variável declarada sem valor recebe automaticamente. string → "",
int → 0, bool → false. Garante que nunca há lixo nem «indefinido».
2.6 [0] [""] — o valor zero de int e de string, e %q mostra as aspas.
2.7 Println imprime e pula de linha. Printf imprime com um modelo de % e não pula
sozinho. Sprintf usa o mesmo modelo, mas devolve o texto em vez de imprimi-lo.
2.8 nil significa «nada» / «vazio». if err != nil pergunta «o erro não está vazio?», ou seja,
«houve um erro?».
2.9 Os três:
- Falta
import "fmt", e se usafmt.Println. puerto := 8080usa:=sobre uma variável que já existe → deve ser=.puertoé declarada e nunca usada (só se imprimenombre) →declared and not used.
Exercícios de código
🔴 Estes sete exercícios ainda não trazem solução de referência — ela será adicionada em uma entrega posterior. Não se inventou código de solução para não publicar um exemplo sem executá-lo primeiro.
2.10 Escreva um programa que declare o seu nome, a sua idade e se você estuda ou trabalha, e os
imprima em três linhas com Printf, usando o verbo correto para cada tipo.
2.11 Escreva func celsiusAFahrenheit(c float64) float64 e teste-a com 0, 37 e 100. A fórmula é
f = c*9/5 + 32. Cuidado: se você escrever c*9/5 com inteiros o resultado é truncado. Por que
aqui isso não acontece?
2.12 Escreva func esPar(n int) bool. Dica: o operador % dá o resto de uma divisão, então
n % 2 == 0 é verdadeiro para os pares.
2.13 Escreva func raizCuadrada(n float64) (float64, error) que devolva erro se n for negativo.
Use math.Sqrt (você precisa de import "math"). Teste-a com 16 e com -4, tratando o erro nos dois
casos.
2.14 Pegue a Fig. 2.10 e acrescente uma coluna que diga SI ou NO conforme a porta seja 443.
Você precisa de uma função nova e de ajustar o modelo do Sprintf.
2.15 (Encontre o erro) Cada um destes fragmentos tem um problema. Diga qual é sem compilar, e depois compile para confirmar:
// (a)
resultado := dividir(10, 2)
// (b)
func sumar(a, b) int { return a + b }
// (c)
var x int = "5"
// (d)
fmt.Printf("el total es %d")
2.16 (Projeto do curso) Este é o primeiro passo do programa que você vai construir durante todo o curso. Escreva um programa que:
- Tenha uma função
revisar(nombre string, puerto int, ms int) stringque devolva uma linha de relatório. - Tenha uma função
clasificar(ms int) string. - Imprima um cabeçalho e cinco serviços.
- No final, imprima quantos dos cinco foram
"rapido". Você vai precisar de uma variável contador e de umif.
Guarde-o: na lição 3 você vai reorganizá-lo com structs.
Como sei que consegui
- Você compilou e rodou, você mesmo e sem copiar/colar, as figuras 2.1 a 2.10 desta lição, e obteve exatamente a saída mostrada.
- Você consegue explicar, sem ver o texto, por que Go é uma linguagem compilada e que consequência prática isso tem para pegar erros antes da produção.
- Você sabe de cor quando usar
:=e quando=, e que erro o compilador dá se você se enganar. - Você consegue citar os quatro tipos básicos (
string,int,float64,bool) e o valor zero de cada um, sem consultar a tabela. - Você escreveu e rodou a sua própria versão do exercício 2.16 (o primeiro passo do
revisor): compila, imprime o cabeçalho, as cinco linhas e a contagem de serviços rápidos. - Você consegue explicar em duas frases por que
if err != nilaparece em toda parte no código Go, e que problema evita em comparação com as exceções de outras linguagens.
Abra o bitacora.md e anote duas coisas: o erro do compilador que mais custou a
você entender, e algo que te surpreendeu. Daqui a três semanas isso vai parecer óbvio e você não vai se
lembrar por que custou — e é justamente isso que convém ter escrito.
Resumo
- Go é uma linguagem compilada: traduz todo o seu código uma vez e produz um executável independente.
- Todo arquivo pertence a um pacote; o pacote
mainé o único que produz um executável. - A execução começa na função
main. importtraz pacotes; Go não carrega nada por padrão.:=declara e atribui;=apenas atribui.- Go não compila se você declara uma variável e não a usa, nem se mistura tipos.
- Os quatro tipos básicos são
string,int,float64ebool. - O valor zero garante que toda variável nasce com um valor válido:
"",0,0,false. Printlnimprime com quebra de linha;Printfusa modelo com%;Sprintfdevolve o texto em vez de imprimi-lo.- Uma função de Go pode devolver vários valores, e o padrão é devolver
(resultado, error). nilsignifica «nada».if err != nilé a forma idiomática de verificar se houve erro, e a linha mais escrita em Go.go runcompila e executa sem deixar arquivo;go builddeixa o executável.
Para ler mais
- A Tour of Go — oficial, interativo. Faça a parte de «Basics» até onde você chegou nesta lição.
- Go by Example — Variables e
Go by Example — Multiple Return Values — o
mesmo padrão
(resultado, error)com programas mínimos que rodam. - Effective Go — ainda não é preciso lê-lo por completo, mas consulte-o se algo desta lição pareceu uma regra arbitrária: ali está o porquê.
Se algo não ficou claro: leia a mensagem de erro completa (Go costuma dizer a linha, a coluna e o que esperava), procure o conceito no Go by Example, e anote a dúvida no diário de bordo mesmo que não a resolva. Uma dúvida escrita pode ser resolvida depois; uma esquecida, não.
Termos desta lição
| compilador | programa que traduz código-fonte em instruções de máquina |
| erro de compilação | erro que impede produzir o executável; é detectado antes de executar |
| função | bloco de código com nome que recebe parâmetros e pode devolver valores |
identificador em branco (_) |
símbolo que descarta um valor de propósito |
int, float64, string, bool |
os quatro tipos básicos |
| linguagem compilada / interpretada | traduz tudo uma vez / linha por linha a cada execução |
main (função) |
ponto de entrada do programa |
main (pacote) |
o único pacote que produz um executável |
nil |
ausência de valor |
| pacote | agrupamento de código relacionado |
| parâmetro | dado que uma função recebe |
Printf / Println / Sprintf |
imprimir com modelo / imprimir com quebra de linha / devolver texto |
| tipo | tipo de dado que uma variável pode guardar |
| valor zero | valor válido que toda variável declarada sem valor recebe |
| variável | espaço de memória com nome que guarda um dado |
verbo de formatação (%d, %s, %q, %t, %v) |
lacuna em um modelo de Printf |
Prefere e-mail? Escreva para hola@habil.mx