Skip to content

Folha de Atalhos da Linguagem Go

Go (também conhecida como Golang) é uma linguagem de programação compilada, de tipagem estática e forte, desenvolvida pela Robert Griesemer, Rob Pike e Ken Thompson da Google. A sintaxe da linguagem Go é semelhante à de C, mas possui funcionalidades como: segurança de memória, GC (garbage collection), tipagem estrutural e computação concorrente no estilo CSP.

Hello world

package main

import "fmt"

func main() {
  message := greetMe("world")
  fmt.Println(message)
}

func greetMe(name string) (string) {
  return "Hello, " + name + "!"
}
$ go build

Variáveis (Variables)

Declaração de variáveis

var msg string
msg = "Hello"

Abreviação (Short declaration)

msg := "Hello"

Constantes (Constants)

const Phi = 1.618

As constantes podem ser caracteres, strings, valores booleanos ou numéricos.

Tipos Básicos

Strings

str := "Hello"
str := `Multiline
string`

O tipo de cadeias de caracteres é string.

Numéricos

Tipos típicos

num := 3          // int
num := 3.         // float64
num := 3 + 4i     // complex128
num := byte('a')  // byte (alias para uint8)

Outros tipos

var u uint = 7        // uint (sem sinal)
var p float32 = 22.7  // 32-bit float

Ponteiros (Pointers)

func main () {
  b := *getPointer()
  fmt.Println("Value is", b)
}
 
func getPointer () (myPointer *int) {
  a := 234
  return &a
}

Um ponteiro aponta para a localização de memória de uma variável. Go possui gestão automática de memória (garbage collection).

Arrays (Matrizes)

// var numbers [5]int
numbers := [...]int{0, 0, 0, 0, 0}

O tamanho dos arrays é fixo.

Slices (Fatias)

slice := []int{2, 3, 4}
slice := []byte("Hello")

Ao contrário dos arrays, os slices têm tamanho dinâmico.

Controlo de Fluxo

Condicionais (if/else)

if day == "sunday" || day == "saturday" {
  rest()
} else if day == "monday" && isTired() {
  groan()
} else {
  work()
}

Declarações dentro do if

if _, err := getResult(); err != nil {
  fmt.Println("Uh oh")
}

A declaração if pode executar uma instrução simples antes da expressão condicional.

Switch

switch day {
  case "sunday":
    // os cases não têm "passagem automática" (fallthrough) por omissão!
    fallthrough

  case "saturday":
    rest()

  default:
    work()
}

Funções

Lambdas

myfunc := func() bool {
  return x > 10000
}

As funções são objetos de primeira classe.

Múltiplos tipos de retorno

a, b := getMessage()
func getMessage() (a string, b string) {
  return "Hello", "World"
}

Retornos nomeados

func split(sum int) (x, y int) {
  x := sum * 4 / 9
  y := sum - x
  return
}

Ao declarar nomes para os valores de retorno, a instrução return (sem parâmetros) retornará as variáveis com esses nomes.

Pacotes (Packages)

Carregamento (Loading)

import "fmt"
import "math/rand"
import (
  "fmt"        // fornece fmt.Println
  "math/rand"  // fornece rand.Intn
)

Ambos são equivalentes.

Aliases (Pseudónimos)

import r "math/rand"
 
r.Intn()

Nomes de chamada (Visibilidade)

func Hello () {
  ···
}

Nomes que começam com letra maiúscula são exportados (públicos).

Packages

package hello

Cada ficheiro de pacote deve começar pela declaração package.

Concorrência

Goroutines

func main() {
  // Um "channel" (canal)
  ch := make(chan string)

  // Iniciar rotinas concorrentes
  go push("Moe", ch)
  go push("Larry", ch)
  go push("Curly", ch)

  // Ler 3 resultados
  // (Como as goroutines são concorrentes,
  // a ordem não é garantida!)
  fmt.Println(<-ch, <-ch, <-ch)
}
 
func push(name string, ch chan string) {
  msg := "Hey, " + name
  ch <- msg
}

Os canais são objetos de comunicação seguros para concorrência, utilizados entre goroutines.

Canais com Buffer (Buffered channels)

ch := make(chan int, 2)
ch <- 1
ch <- 2
ch <- 3
// fatal error:
// all goroutines are asleep - deadlock!

Os canais com buffer limitam o número de mensagens que podem armazenar.

Fechar canais

ch <- 1
ch <- 2
ch <- 3
close(ch)

Iterar sobre um canal até ser fechado:

for i := range ch {
  ···
}

Verificar se está fechado (ok == false):

v, ok := <- ch

Controlo de Erros

Defer

func main() {
  defer fmt.Println("Done")
  fmt.Println("Working...")
}

Adia a execução de uma função até que a função envolvente retorne. Os parâmetros são avaliados imediatamente, mas a chamada da função só ocorre no final.

Funções Adiadas (Deferred functions)

func main() {
  defer func() {
    fmt.Println("Done")
  }()
  fmt.Println("Working...")
}

As Lambdas são ideais para blocos de adiamento (defer blocks).

Estruturas (Structs)

Definição

type Vertex struct {
  X int
  Y int
}

func main() {
  v := Vertex{1, 2}
  v.X = 4
  fmt.Println(v.X, v.Y)
}

Literais

v := Vertex{X: 1, Y: 2}
// Nomes de campos podem ser omitidos
v := Vertex{1, 2}
// Y é implícito (zero value)
v := Vertex{X: 1}

Também pode especificar os nomes dos campos.

Ponteiros para estruturas

v := &Vertex{1, 2}
v.X = 2

Quando v é um ponteiro, v.X e (*v).X são equivalentes.

Métodos

Recetor (Receiver)

type Vertex struct {
  X, Y float64
}
func (v Vertex) Abs() float64 {
  return math.Sqrt(v.X * v.X + v.Y * v.Y)
}
 
v: = Vertex{1, 2}
v.Abs()

Não existem classes, mas pode usar recetores para definir funções em tipos.

Alteração (Mutation)

func (v *Vertex) Scale(f float64) {
  v.X = v.X * f
  v.Y = v.Y * f
}
 
v := Vertex{6, 12}
v.Scale(0.5)
// `v` é atualizado