DEV Community

Erick Takeshi
Erick Takeshi

Posted on • Edited on

#3 - Learning Go - Blocos, Shadowing e Estruturas de controle

Nada de especial aqui, anotações pertinentes do capítulo 4 do livro Learning Go - Blocks, Shadows, and Control Structures.

Um comentário especial da minha parte:

Esses conceitos de block e shadowing existem em praticamente todas as linguagens e, embora comum, sempre costumam causar bugs inesperados. A maioria das pessoas acaba comendo bola com closures, shadowing e etc.

Então , meu conselho é prestar bastante atenção nisso e sempre manter o buffer das variáveis em contexto hehe.

Seguem as anotações:

Blocks

Qualquer lugar onde uma declaração de variável pode ocorrer é um bloco.
Tudo que for declarado fora de uma função esta no package block.

Os parâmetros e tudo que for definido dentro dos {} de uma função estão em um bloco.

Dentro de uma função, todo par de {} define um bloco também (estruturas de controle, loop, etc).

Você consegue acessar um identificador definido em blocos de fora em blocos de dentro.

Shadowing

Ao declarar uma variável em um bloco interno com o mesmo nome de outra variável de um bloco externo estamos fazendo shadowing, ou seja, a variável do bloco externo não é mais acessível e fica “sobreposta” pelo valor da nova variável declarada no bloco interno.

Detecção de shadowing

Existe um linter chamado shadow que ajuda a detectar shadowing e é muito recomendado que faça parte do seu pipeline de build.

Universe Block

Go é uma linguagem enxuta com somente 25 keywords, então algumas palavras que seriam esperadas a serem keywords na verdade acabam sendo identificadores pré declarados, como o caso de tipos built-in (int , string , etc), constantes (true , false ), funções (make , close) e até mesmo nil .

Todos esses identificadores são declarados em um bloco que contém todos os outros blocos, que é chamado de universe block, devido a isto devemos ter cuidado e não fazer shadowing destes valores. Teríamos comportamentos totalmente inesperados ao redefinir o valor de true ou false por exemplo.

If statement

Ifs em Go são basicamente idênticos a outras linguagens, única diferença é que é possível declarar variáveis para uso dentro dos blocos do if else diretamente antes da condição.

Loops

Em Go, existe somente uma forma de construis loops, sendo o for a única keyword pra este fim. Existem algumas formas diferentes de se usar o for em Go.

for-range é a forma utilizada para iterar sobre elementos de tipos built-in (strings, arrays, slices e maps). No for-range podemos ignorar tanto a variável de posição (a primeira na ordem), quanto a variável de valor (ultimo na ordem). Parar ignorar a variável de posição podemos utilizar um _ como nome da variável, para ignorar a variável de valor podemos simplesmente não declara-la.

Iterando mapas

É importante destacar que a ordem não é garantida quando iteramos sobre mapas.

Iterando strings

Na iteração de strings é retornado runes em cada iteração, tendo um tratamento especial pra quando um caractere (rune) seja representado por múltiplos bytes. Nesse caso, a variável de posição é incrementada pelo número de bytes que a rune possui, a variável de valor assume o valor da representação UTF-8 de 32-bits. Caso não seja possível encontrar uma representação UTF-8 válida, o Unicode replacement character (valor hex 0xfffd) é retornado como valor.

A variável de valor do for-range é uma cópia

Importante mencionar que a variável de valor do for-range é uma cópia do valor sendo iterado, ou seja, modificar a variável não vai afetar em nada o elemento que esta sob iteração.

Label em loops

Podemos “nomear” loops para que consigamos utilizar o break ou continue de loops externos em loops internos.

Switch

Os case são mutuamente exclusivos, ou seja, quando algum case é atingido o switch para.

Existe a keyword fallthrough que permite que o switch continue, porém não é muito idiomático utilizá-lo.

Quando usar if-elses ou switch?

O switch agrupa condicionais relacionadas, ou seja, quando haver uma relação entre as condicionais usar o switch.

goto

Evite usar goto quase sempre.

Existem alguns poucos casos onde o goto pode simplificar a leitura do código, principalmente quando usamos flags booleanas para controlar o fluxo de alguma forma.

func main() {
    a := rand.Intn(10)

    for a < 100 {
        if a%5 == 0 {
            goto done
        }

        a=a*2+1
    }

    fmt.Println("do something when the loop completes normally")
done:
    fmt.Println("do complicated stuff no matter why we left the loop")
    fmt.Println(a)
}
Enter fullscreen mode Exit fullscreen mode

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:

Top comments (0)