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 »

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 »

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 »

Trabalhando com variáveis

Embora pareça um assunto sem muito conteúdo, é muito importante saber alguns detalhes de como trabalhar com variáveis em Go.

A primeira coisa que precisamos saber sobre variáveis em Go, é que elas tem escopo, ou seja, dependendo de onde ela for criada você estará limitando os locais em que ela estará disponível.

No exemplo abaixo, vamos criar 3 variáveis com 3 escopos diferentes.

var connection = database.Connect()

func Insert(data interface{}) string {
    err := connection.Create(data)
    if err != nil {
        msg := fmt.Sprintf("falha ao tentar inserir: %v", err)
        return msg
    }

    return "inserido com sucesso sucesso!"
}

connection: Essa variável tem um escopo global, ou seja, estará disponível para ser utilizada em qualquer parte do package onde ela foi criada.

Leia mais »

Escrevendo testes unitários

Testes unitários nos ajudam muito a tentar manter a quantidade de bugs baixa, já que podemos testar várias hipóteses de forma automática. E por ser automatizada, a cada mudança que fazemos, os testes unitários também nos ajudam a garantir que não quebramos o sistema em partes que nem tocamos mas que dependem das mudanças que fizemos.

Embora exista alguns packages que ajudam na escrita dos testes unitários, a recomendação do time de desenvolvimento da linguagem é que os testes sejam escritos usando o package nativo da linguagem, pelo simples fato de que um package externo pode adicionar algum bug ou realizar algum teste de forma incorreta.

Antes de começar a escrever os testes, vamos criar um arquivo chamado soma.go e escrever uma pequena função que soma N valores.

package soma


func Soma(valores ...int) (total int) {
    for _, valor := range valores {
        total += valor
    }

    return
}
Leia mais »

Escrevendo funções em GO

Hoje vamos falar um pouco sobre um dos itens mais básico e importante de qualquer linguagem de programação, funções.

Funções nos ajudam a dividir o código de forma a ser reutilizável, diminuindo a quantidade de escrita de um bloco de código e facilitando a manutenção do programa. É claro que se alguém fizer uma função com 17 mil linhas de código, toda bagunçada e confusa, nada do que eu disse antes se torna verdade, mas sabemos que ninguém aqui faz ou já fez isso, certo? 😀

Assim como em qualquer outra linguagem, a premissa de uma função em Go é que ela execute somente aquilo que ela nasceu para executar. Dessa forma diminuímos a complexidade da função e aumentamos a possibilidade de reutilização da mesma.

Leia mais »

Escrevendo logs para um arquivo customizado

Uma parte muito importante do desenvolvimento de um software, mas que normalmente acaba esquecida ou sendo feita de qualquer forma são os logs da aplicação.

Logs ajudam muito em processos de debug em produção, pois podemos consultar-los para tentar entender o que está acontecendo sem ter que parar o programa em execução.

Usar somente o log.Println não resolve nosso problema, já que dessa forma os logs serão impressos somente no terminal. O ideal então é escrever os logs em arquivos.

Para que o package log do Go escreva os logs em arquivo ao invés do terminal, precisamos executar alguns passos antes de escrever nossa mensagem de log. Para que possamos reutilizar a escrita em qualquer parte do nosso programa, vamos criar um package com todas as configurações necessárias.

Primeiramente vamos criar uma pasta logs e um arquivo log.go. Nesse arquivo, vamos criar uma função Write para escrever nossos logs.

Leia mais »

As várias formas de fazer looping em Go

A maioria das linguagens que já trabalhei tem vários comandos para fazer looping, como por exemplo for, foreach, while, do..while e goto.

Já em Go, nós só temos o comando for, porém ele tem várias assinaturas, o que no final faz com que ele possa ter o comportamento equivalente a um for, foreach e while de outras linguagens.

Vamos começar pela forma mais básica, que é a mesma assinatura que outras linguagens utilizam.

for i := 0; i < 10; i++ {
    fmt.Println(i)
}

nomes := []string{Tiago, Lucas, Pedro, Luana, Dani}
for i := 0; i < len(nomes); i++ {
    fmt.Println(nomes[i])
}
Leia mais »