Manipulação Dinâmica e Controle de Fluxo em Go

Inspeção Dinâmica com Reflect

O pacote nativo reflect possibilita a inspeção e modificação de estruturas durante a execução do programa. Isso é particularmente útil quando se necessita acessar campos de uma struct utilizando strings como identificadores, ou quando o tipo exato da variável só é conhecido em tempo de execução.

Dentro deste pacote, destacam-se dois componentes fundamentais: reflect.Type, que descreve o tipo da variável, e reflect.Value, que contém o valor atual. Para instanciá-los, utilizam-se as funções reflect.TypeOf e reflect.ValueOf, respectivamente.

Obtenção de Tipos e Valores

O exemplo abaixo demonstra como recuperar informações básicas sobre uma variável simples:

package main

import (
	"fmt"
	"reflect"
)

func main() {
	variable := 42
	fmt.Println(reflect.TypeOf(variable))  // int
	fmt.Println(reflect.ValueOf(variable)) // 42
}

Acessando Campos de Structs

Para estruturas mais complexas, é possível iterar sobre os campos ou acessá-los diretamente pelo nome ou índice. Note que para modificar valores, os campos devem ser exportados (iniciados com letra maiúscula).

package main

import (
	"fmt"
	"reflect"
)

type Usuario struct {
	Nome  string
	Cidade string
}

func main() {
	dados := Usuario{"Carlos", "Lisboa"}
	v := reflect.ValueOf(dados)

	// Total de campos
	fmt.Println(v.NumField()) 

	// Acesso via índice
	fmt.Println(v.Field(0).String()) 

	// Acesso via nome
	campo := "Cidade"
	fmt.Println(v.FieldByName(campo).String())
}

Modificação de Valores via Ponteiro

A alteração de valores exige que se passe o endereço da struct para o reflexo. O método Elem() é utilizado para dereferenciar o ponteiro. Além disso, o método CanSet() verifica se a modificação é permitida.

package main

import (
	"fmt"
	"reflect"
)

type Perfil struct {
	Titulo string
	Pais   string
}

func main() {
	target := "Titulo"
	p := &Perfil{}
	
	v := reflect.ValueOf(p).Elem()
	
	// Verifica permissão de escrita
	fmt.Println(v.FieldByName(target).CanSet())

	// Atribuição de novos valores
	v.FieldByName(target).SetString("Engenheiro")
	v.FieldByName("Pais").SetString("Brasil")
	
	fmt.Println(p) // &{Engenheiro Brasil}
}

Uso de Tags em Structs

Tags são metadados anexados aos campos da struct, frequentemente usados para serialização. Elas podem ser lidas através do tipo refletido.

package main

import (
	"fmt"
	"reflect"
)

type Dados struct {
	ID int `json:"identificador"`
}

func main() {
	t := reflect.TypeOf(Dados{})
	field, _ := t.FieldByName("ID")
	
	fmt.Println(field.Tag)           // json:"identificador"
	fmt.Println(field.Tag.Get("json")) // identificador
}

Registro de Eventos (Logging)

O pacote log oferece funcionalidades básicas para registro de saída. As principais funções incluem Print para informação padrão, Panic que registra e entra em pânico, e Fatal que registra e encerra o processo imediatamente. Por padrão, as mensagens incluem carimbos de tempo.

É possível configurar a saída para arquivos personalizados com prefixos específicos:

package main

import (
	"log"
	"os"
)

func main() {
	arquivo, _ := os.OpenFile("./registro.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	defer arquivo.Close()

	logger := log.New(arquivo, "[APP]", log.Ldate|log.Ltime)
	logger.Println("Sistema iniciado com sucesso")
}

Controle de Tempo e Pausas

O pacote time gerencia a execução temporal. A função Sleep bloqueia a goroutine atual por uma duração específica. Já a função AfterFunc agenda uma execução futura, mas requer que o programa principle permaneça ativo até que o tempo expire.

Pausa na Execução

package main

import (
	"fmt"
	"time"
)

func main() {
	fmt.Println("Inicio")
	time.Sleep(2 * time.Second)
	fmt.Println("Fim após pausa")
}

Execução Diferida

Ao usar timers assíncronos, é crucial garantir que a thread principal não termine prematuramente:

package main

import (
	"fmt"
	"time"
)

func main() {
	fmt.Println("Agendando tarefa")
	
	time.AfterFunc(3*time.Second, func() {
		fmt.Println("Tarefa executada")
	})
	
	// Bloqueio necessário para aguardar o timer
	time.Sleep(4 * time.Second)
	fmt.Println("Encerrando")
}

Tags: Golang reflect-package standard-log time-management

Publicado em 9-29 14:35