Como injetar valores em variáveis com ldflags

Uma feature pouco conhecida para quem está iniciando na linguagem Go, é a capacidade de injetarmos valores em variáveis durante o processo de build. Embora possa parecer um tanto quanto estranho fazer isso, essa técnica nos possibilita adicionar informações como versão, data e commit do build, sem a necessidade de commitar essas informações. Embora possamos criar essas variáveis no mesmo arquivo onde estará a função main da aplicação, eu prefiro fazer algo que possa ser reutilizado.

Definindo as variáveis de build

Por isso, pensando em um repositório onde haverão várias aplicações, ou até mesmo em uma estrutura de monorepo, vamos criar um package dentro da pasta pkg chamado build. Dentro do package, vamos criar um arquivo chamado version.go com o seguinte conteúdo.

Leia mais »
photo of a turtle swimming underwater

O que é e como utilizar o tipo enum

Muitas vezes, dentro dos sistemas que desenvolvemos, temos valores constantes. Dentre outras possibilidades, um exemplo desses valores, seria a representação do status de um cadastro. Nesse caso, pense em um status onde temos variações além de ativo e inativo.

Caso esses status sejam definidos como string, sua validação dentro do sistema pode acabar se tornando uma grande dor de cabeça. Além, é claro, de “inflar” o binário. Afinal, em cada validação teremos 2 strings (valor esperado e valor sendo validado).

Na tentativa de evitar esses problemas, podemos utilizar o famoso tipo enum. Se você não está familiarizado com esse tipo, ele nada mais é do que um tipo de tamanho limitado ou fixo.

Para ficar mais claro, vamos escrever um pouco de código. Seguindo a ideia apresentada no inicio do post, vamos criar um tipo enum para validar status de um cadastro.

Leia mais »
rock formation

Como utilizar “herança” em interfaces

Embora o Golang não implemente orientação a objetos, de forma superficial, sua estratégia de embedding – que inclusive é muito utilizada nos packages nativos da linguagem – é muito parecida com a famosa herança.

Nesse post, vou mostrar como utilizar essa estratégia para que possamos ter interfaces mais granulares.

Antes de começar, como o objetivo desse post é exemplificar como utilizar embedding em interfaces, não vamos implementar os métodos. Também não vamos mostrar como utilizá-las em assinaturas de funções/métodos. Caso você queria saber mais sobre como utilizar interfaces, recomendo a leitura do post “Trabalhando com Interfaces”.

Sem mais delongas, vamos criar 3 interfaces. Writer, Reader e Closer.

type Writer interface {
	Write(p []byte) (n int, err error)
}

type Reader interface {
	Read(p []byte) (n int, err error)
}

type Closer interface {
	Close() error
}
Leia mais »
snow top mountain under clear sky

Como implementar uma função utilizando context

Nesse post vamos implementar uma função que utiliza context. No exemplo de chamada, vou utilizar o context WithTimeout. Dessa forma, conseguiremos fazer a função ser cancelada automaticamente, caso o tempo de execução dela ultrapasse o tempo estipulado no context.

Vamos iniciar criando uma função com o nome doSomeHeavyWork.

func doSomeHeavyWork(ctx context.Context, msg string) {
}

Para simular um processamento longo, vamos adicionar uma goroutine com um sleep de 2 segundos. Essa goroutine irá receber um channel do tipo bool. Ele irá sinalizar que a goroutine foi finalizada.

Leia mais »
brown and pink pendant

Como utilizar tags customizadas

A utilização de tags ajuda muito na hora de escrever funções genéricas. Um exemplo disso é a função json.Marshal. Não importa como sua struct está estruturada, se ela tiver a tag json no atributo, a função consegue fazer o que precisa ser feito.

Se você não sabe do que eu estou falando, te convido à ler o post “O que são e como utilizar tags”. Lá dou todo o contexto para que você possa entender melhor o que vamos fazer aqui nesse post.

Além do package json, existe uma infinidade de outros packages que tiram vantagem da utilização das tags. Esses packages vão desde encoders até ORMs.

Embora existam packages que ajudem na validação de campos, para fins didáticos, vamos criar uma função que utiliza da tag required para saber se um campo é ou não obrigatório.

func validateFields(stc any) error {

}
Leia mais »
a person sitting on wooden planks across the lake scenery

Onde e qual Context utilizar

O package Context do Go é algo que vemos sendo cada vez mais utilizados por grandes packages. No entanto, não é nada estranho ver pessoas sem saber qual context utilizar dentre os diferentes tipos disponíveis.

Nesse post, vou falar sobre os diferentes tipos de context que temos, como fazemos para obtê-los e onde normalmente são utilizados.

Se você nunca viu esse package, aconselho assistir o vídeo Como funciona e para que serve o package Context (Golang) que temos no nosso canal do YouTube.

Bora começar?

Leia mais »
hanging decor lot

O que são e como utilizar tags em structs

Uma feature pouco comentada porém muito útil na linguagem Go, pelo menos no meu ponto de vista, é a tag.

As tags são marcações que colocamos nas propriedades de uma struct. Essas marcações funcionam como metadata para outros packages poderem realizar operações.

Para ficar mais claro, vamos criar um struct comum.

type Pessoa struct {
  Nome      string
  Documento string
  Idade     uint8
}
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 »

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 »