DEV Community

Erick Takeshi
Erick Takeshi

Posted on

#4 - Learning Go - Funções

Sem muitas novidades por aqui, mais um compilado de anotações do capítulo 5 sobre funções.

Este capítulo está intimamente ligado com o próximo capítulo sobre ponteiros, então é interessante ler os dois para se ter um entendimento maior sobre como funções se comportam em Go.

Estou pensando em criar uma pausa nos capítulos do livro e tentar fazer um artigo simples sobre makefiles e como estruturar um para projetos em Go, acredito ser um bom ponto de início pra aprender sobre projetos production ready! Pretendo dar uma olhada nisso essa semana ainda.

Sem mais delongas, seguem as anotações:

Função main é o entrypoint de qualquer programa em Go.

Se uma função retorna um valor é obrigatório utilizar o return em algum ponto do seu corpo.

Go não possui parâmetros com nomes e opcionais, para simular essa feature podemos utilizar um struct como parâmetro da função e preencher o struct conforme necessidade.

Número variável de parâmetros

O parâmetro variável precisa ser o último da lista de parâmetros de uma função (ou o único). Dentro da função é criado um slice contendo os valores passados a função.

Múltiplos valores de retorno

Normalmente é utilizado para retornar erros da execução de uma função (padrão comma ok).

O erro, por convenção, é o último ou único retorno de uma função (quando queremos dar suporte a tratamento de erro por parte do código que chama a função).

Não colocar parêntesis nos valores de retorno de uma função, gera um erro de compilação.

Gera erro de compilação não fazer o assignment de todos os valores retornados de uma funciona que retorna múltiplos valores.

Ignorando valores de retorno

Podemos ignorar o valor de retorno de uma função ao fazer o assignment do valor de retorno a um _ , pra todos os valores que queremos ignorar.

Também é possível invocar uma função e não fazer o assignment de nenhum dos valores, ignorando todos eles, porém não é muito idiomático fazer isto.

Valores de retorno com nome

Em Go podemos dar nomes e criar variáveis que serão utilizadas como valores de retorno de uma função.

Essas variáveis de retorno são inicializadas com o valor zero do seu tipo declarado.

Não é necessário atribuir valores a essas variáveis de retorno.

Não é necessário utilizar essas variáveis como o parâmetro para o return da função.

Dica: Em algumas situações utilizar valores de retorno com nome deixa o código mais legível (e no caso de defer é imprescindível), porém, como pode haver o problema de shadowing e pelo fato de podermos simplesmente ignorar as variáveis, o seu valor se torna limitado.

Blank returns

Quando estamos utilizando valores de retorno com nome, podemos simplesmente chamar return dentro de uma função e iremos retornar o valor contido nas variáveis de retorno.
Evite ao máximo utilizar esse comportamento!

É um comportamento que deixa o código mais difícil de entender, uma vez que um leitor precisa ficar indo e vindo de diferentes partes do código, relembrando o ultimo valor que foi atribuído a cada variável de retorno.

Funções são valores

O tipo de uma função é construído a partir da keyword func e o tipo dos seus parâmetros e valores de retorno, essa combinação também é conhecida como assinatura da função.

Como funções são valores, podemos guardar seu valor em variáveis e associa-las a diversas estruturas de dados, como mapas.

Funções anônimas

Em Go funções anônimas são úteis em duas situações:

  • em instruções defer
  • ao lançar goroutines

Closures

Funções declaradas dentro de outra função são chamadas de closure. Isso significa que essas funções tem a capacidade de acessar e modificar variáveis da função de fora (que a contém).

Funções como parâmetro

Como funções em Go são valores, podemos passar funções como parâmetro para outras funções, além disso, podemos aproveitar de closures para “capturar” variáveis de outros escopos e utiliza-las dentro de outras funções. Um bom exemplo de aplicação deste conceito é no método Slice do package sort da standard library, que faz a ordenação de um slice baseado no retorno de uma função que deve categorizar dois elementos do slice.

Funções como valor de retorno

Assim como funções podem ser usadas como parâmetro, elas também podem ser usadas como valor de retorno de outra função, se valendo de Closures e “capturando” variáveis consigo. Um exemplo prático de aplicação deste conceito é o de middlewares em web servers.

defer

defer é uma keyword usada em Go para declarar uma função que será executada sempre, independente da função que a contém ter finalizado com sucesso ou não. Sua aplicação prática é a de executar código de limpeza e liberação de recursos, como fechar arquivos ou conexões de rede.
Uma função pode declarar múltiplos defer , o último declarado vai rodar primeiro (ordem last-in-first-out).

Go é call by value

Call by value significa que toda vez que uma variável é passada como parâmetro de uma função, em Go, sempre será criada uma cópia do valor desta variável.

Maioria dos tipos primitivos se comportam da maneira padrão esperada, ou seja, você recebe uma cópia direta e modificar seu valor não interfere no valor externo, porém, alguns tipos se comportam de maneira diferente, como maps e slices.

Ao modificar maps, as modificações são refletidas nas variáveis externas, ao modificar slices, as modificações de troca de valores são refletidas, porém não é possível aumentar o tamanho de um slice (dar append).

Esse comportamento de maps e slices se deve ao fato de essas estruturas serem implementadas com ponteiros.

Outros capítulos

Esta é uma série onde pretendo fazer anotações de todos os capítulos relevantes do livro Learning Go, seguem os links para os capítulos anteriores e futuros:
#3 - Learning Go - Blocos, Shadowing e Estruturas de controle
#2 - Learning Go - Tipos compostos
#1 - Learning Go - Tipos primitivos e declarações de variáveis

Top comments (0)