Desafio Go

Enum com String e Bit Flags com Verificação de Múltiplas Flags

Enunciado

Crie um enum Nivel (int) com Baixo, Medio, Alto usando iota. Implemente o método String() para Nivel. Defina também um tipo Permissao (uint) com as flags Ler, Escrever, Executar usando 1 << iota. No main, crie uma permissão p := Ler | Executar, verifique se ela contém Ler e Escrever (imprima true ou false para cada), e imprima o nível Alto usando seu método String().

Requisitos

  • Definir type Nivel int e type Permissao uint.
  • Usar iota para o enum Nivel e 1 << iota para as permissões.
  • Implementar String() string para Nivel.
  • Verificar a presença de Ler e Escrever na permissão p e imprimir os resultados.
  • Imprimir o nível Alto usando String().

Código inicial

package main

import "fmt"

// TODO: defina Nivel, Permissao e seus métodos

func main() {
	// TODO: implemente a lógica
}

Saída esperada

Tem leitura? true
Tem escrita? false
Nível: Alto
Ver dica

Para o método String de Nivel, use um array de strings indexado pelo valor do nível. Para as permissões, use p&Ler != 0.

Mostrar solução
package main

import "fmt"

type Nivel int

const (
	Baixo Nivel = iota // 0
	Medio              // 1
	Alto               // 2
)

// String implementa fmt.Stringer para Nivel.
func (n Nivel) String() string {
	niveis := [...]string{"Baixo", "Medio", "Alto"}
	if n < Baixo || n > Alto {
		return fmt.Sprintf("Nivel(%d)", int(n))
	}
	return niveis[n]
}

type Permissao uint

const (
	Ler    Permissao = 1 << iota // 1 << 0 = 1
	Escrever                     // 1 << 1 = 2
	Executar                     // 1 << 2 = 4
)

func main() {
	p := Ler | Executar // 1 | 4 = 5
	fmt.Println("Tem leitura?", p&Ler != 0)
	fmt.Println("Tem escrita?", p&Escrever != 0)
	fmt.Println("Nível:", Alto)
}

Passo a passo

  1. Definimos type Nivel int e o bloco const com iota para Baixo, Medio, Alto (0, 1, 2).
  2. Implementamos String() string para Nivel usando um array de strings e verificação de limites.
  3. Definimos type Permissao uint e o bloco const com 1 << iota para Ler, Escrever, Executar (1, 2, 4).
  4. No main, criamos p := Ler | Executar (1 | 4 = 5).
  5. Verificamos a presença de Ler e Escrever com p&Ler != 0 e p&Escrever != 0.
  6. Imprimimos Alto, que chama automaticamente o método String().

Por que funciona

O iota gera valores sequenciais para o enum, e o método String() permite uma representação legível. Para as permissões, cada flag é uma potência de dois, permitindo combinações com | e verificações com &. A verificação p&flag != 0 isola o bit correspondente.

Erros comuns

  • Não implementar String() corretamente: se o array não cobrir todos os valores, pode causar panic. Sempre verifique os limites.
  • Usar p&Ler == 1 em vez de != 0: funciona aqui, mas se a flag tiver múltiplos bits, a comparação falha. Prefira != 0.
  • Esquecer de tipar a primeira constante do bloco const de permissões: Ler = 1 << iota sem Permissao faria as constantes serem int não tipadas, quebrando a tipagem forte.

Outra forma de resolver

Para verificar múltiplas flags de uma vez, use p&(Ler|Escrever) == (Ler|Escrever). Isso é útil quando você precisa que todas estejam presentes.

Saída esperada

Tem leitura? true
Tem escrita? false
Nível: Alto