Como fazer encadeamento de métodos (chaining)

Chaining de métodos é uma técnica muito utilizada em linguagens como PHP, Java e C#. Se você não está familiarizado com o termo, não se preocupe, pois essa é uma técnica muito simples. Ela consiste em retornar um objeto para que outro método possa ser chamado sem a necessidade de atribuição a uma outra variável.

Essa técnica é muito utilizada em ORMs como o GORM, para construção de queries mais complexas.

No vídeo que postamos no nosso canal do youtube mostrando como construir uma API completa com go-chi e postgres (link para o vídeo), também podemos ver essa técnica sendo utilizada para fazer o decode da request para uma struct.

Para entender melhor seu funcionamento, vamos criar uma struct com 100% de seus atributos privados.

Leia mais »

Quando utilizar generics?

Assim como as goroutines, uma das dúvidas que mais tenho visto quando o assunto é generics, a nova feature do Go 1.18, é quando ela deve ser utilizada.

Nesse post, baseado no post publicado em 12 de abril no blog oficial do Go (When to use generics), vou tentar passar um pouco das dicas dadas pelo Ian Lance Taylor.

Ele começa o primeiro vídeo falando sobre como escrever código Go. De forma muito simples e em tradução livre ele diz:

Escreva código, não desenhe tipos.

Leia mais »

Orientação a objetos em Go

Go não é uma linguagem de programação orientada a objetos. No entanto, algumas de suas features fazem com que seja possível trabalhar com algo muito parecido.

Nesse post vou falar sobre como podemos utilizar essas features para ter alguns comportamentos parecidos com orientação a objetos.

Classe

Go não implemente o conceito de classe como podemos encontrar em outras linguagens. Porém, para suprimir essa necessidade, podemos utilizar as structs ou estruturas.

type Foo struct {}

type bar struct {}

Esse tipo de dado composto nos permite criar campos, que podemos pensar como se fossem atributos. Também é possível adicionar métodos as structs.

Leia mais »

A diferença entre array e slice

Quando comecei aprender Go, eu achava que slice e array eram a mesma coisa. Depois de algum tempo que fui descobrir e entender a diferença entre eles.

Nesse post vou falar sobre a diferença entre eles e refatorar o código do vídeo sobre bubble sort que publicamos lá no canal, para que ele funcione com arrays ao invés de slice.

Para começar, vamos entender o que são arrays.

Um array é um tipo de dado composto, de tamanho fixo com zero ou mais elementos de um tipo específico. Por ter tamanho fixo, raramente vemos o uso de arrays em programas Go.

Existem três formas básicas para se iniciar um array.

Leia mais »

Múltiplos channels e a cláusula select

Dando continuidade ao nosso estudo de goroutines e channels, nesse post vamos falar sobre uma cláusula pouco utilizada.

Antes de começar, vou deixar os links para os outros posts caso você tenha perdido algum da série.

A cláusula select é utilizada para que uma função consiga trabalhar com múltiplos channels. Ela bloqueia a execução da função até que um dos channels esteja pronto para ser executado. Caso mais de um channel esteja pronto para ser executado, ela selecionará de forma aleatória qual executar.

Para tentar ficar um pouco mais claro, vamos escrever um pequeno programa para ilustrar o comportamento.

Leia mais »

Formatando strings para logs e mensagens

Se você já trabalha com Go a algum tempo, muito provavelmente você já conhece e utiliza o %s, %d e o \n. Pois bem, nesse post vamos abordar os principais os verbos disponíveis para te ajudar na hora de formatar uma string em Go.

Se você é novo em Go, saiba que os verbos que vamos abordar nesse post podem ser utilizados com as funções Printf, Sprintf e Errorf do package fmt, assim como as funções Fatalf, Panicf e Printf do package log.

Para começar, vamos a um exemplo bem simples utilizando somente os dois verbos que já comentamos. Digamos que nosso programa, sempre que alguém pede um novo café, exibe o nome da pessoa e a quantidade de café que ela consumiu no dia.

func main() {
    name := "Tiago"
    coffee := 5

    fmt.Printf("Olá %s, você já bebeu %d cafés hoje", name, coffee)
}

Ao ser executado, o %s será substituido pelo conteúdo da váriavel name, e o %d pela vafiável coffee.

Leia mais »

Trabalhando com switch/case

Dando continuidade nos nossos posts sobre comandos core da linguagem, nesse post vamos falar sobre o switch/case.

Esse comando é bem conhecido e existe em quase toda linguagem de programação. Se você nunca ouviu falar dele, tente imaginá-lo como uma forma mais curta de encadear um monte de if - else.

Uma diferença que vale ressaltar entre Go e as outras linguagens é que ao contrário das outras linguagens, o Go só executa o caso selecionado eliminando assim a necessidade de colocar um break.

Em sua forma mais básica, ele recebe um valor no inicio e depois checa se esse valor é igual algum dos casos definidos, e caso não seja, executa a caso padrão.

Para iniciar, vamos a um exemplo básico.

switch os := runtime.GOOS; os {
case "darwin":
    fmt.Println("MAC OS")
case "linux":
    fmt.Println("Linux")
default:
    fmt.Printf("%s \n", os)
}
Leia mais »

Convertendo tipos de dados

Em linguagens fortemente tipadas, muitas vezes precisamos fazer conversões dos tipos das nossas variáveis para poder executar algum tipo de função interna. Uma das conversões mais comum que acontecem é a de int ou float para string e vice versa.

Também pode acontecer conversões dentro do mesmo “grupo”, por exemplo de int32 para int16. Porém, embora pertençam ao mesmo “grupo”, temos que ficar atentos ao tamanho máximo que cada um desses tipos comportam, pois caso o valor extrapole a capacidade do tipo destino, a conversão irá dar errado.

var i32 int32 = 10
i16 := int16(i32)
fmt.Printf("%T - %d", i16, i16)

No exemplo acima, tudo funcionará bem, pois 10 é um valor que os dois tipos de dados comportam. Agora se o valor de i32 fosse 32769, a conversão para int16 retornaria -32767, e se fosse algo maior ainda, como por exemplo 132769, a conversão retornaria 1697.

Leia mais »

O que são e como funcionam as Goroutines

Na semana passada explicamos a diferença entre concorrência e paralelismo (link do post), o que serviu de base para o post de hoje, onde vamos explicar as famosas goroutines.

Goroutines são funções ou métodos executados em concorrência. Podemos pensar nelas como uma especie de lightweight thread que são gerenciadas pelo runtime do Go.

Chamamos de lightweight thread pois o custo para sua criação é muito menor quando comparada com um thread de verdade. Outro ponto positivo é que o runtime consegue aumentar ou diminuir a quantidade de goroutines de acordo com a necessidade da aplicação, enquanto o número de thread normalmente é fixo.

Leia mais »

Entendendo os tipos de dados e suas capacidades

Embora seja um assunto não muito abordado, pelo menos no meu ponto de vista, entender todos os tipos de dados que uma linguagem oferece, ajuda muito no momento de criar um programa, principalmente do ponto de vista de performance e eficiência no consumo de recursos.

Por isso, no post de hoje vamos ver todos os tipos de dados básicos que temos na linguagem e suas capacidades.

Bool

O tipo booleano, é um dos tipos mais básicos e comum no mundo da tecnologia.

Embora em algumas linguagens ele possa ser definido com 0 e 1, em Go os únicos valores aceitos são true ou false.

String

Conjunto de todos os caracteres de 8-bit, ou seja, qualquer tipo de texto.

Uma string pode ser vazia, mas não pode ser nula (nil).

Leia mais »