Menu
Coddy logo textTech

Noções Básicas de Reflection

Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy. Lição 83 de 107.

Reflexão permite que um programa examine e manipule sua própria estrutura em tempo de execução. O pacote reflect do Go oferece esse recurso, permitindo inspecionar tipos, ler campos de structs e chamar métodos dinamicamente.

Os dois tipos fundamentais em reflexão são reflect.Type e reflect.Value. Você os obtém usando reflect.TypeOf() e reflect.ValueOf():

import "reflect"

type Person struct {
    Name string
    Age  int
}

p := Person{Name: "Alice", Age: 30}

t := reflect.TypeOf(p)
v := reflect.ValueOf(p)

fmt.Println(t.Name())       // Person
fmt.Println(t.Kind())       // struct
fmt.Println(v.NumField())   // 2

Você pode iterar pelos campos da struct para examinar seus nomes, tipos e valores:

for i := 0; i < t.NumField(); i++ {
    field := t.Field(i)
    value := v.Field(i)
    fmt.Printf("%s: %v\n", field.Name, value)
}
// Saída:
// Name: Alice
// Age: 30

A reflexão é poderosa, mas envolve compensações: ignora a verificação de tipos em tempo de compilação, é executada mais lentamente do que o acesso direto e torna o código mais difícil de entender. Use-a com moderação para tarefas como a serialização JSON, o mapeamento de ORM ou a criação de utilitários genéricos quando o tipo não é conhecido em tempo de compilação.

challenge icon

Desafio

Fácil

Vamos criar um inspetor de structs que usa reflexão para examinar qualquer struct e relatar sua estrutura! Este é um caso de uso prático da reflexão: criar utilitários que funcionam com tipos desconhecidos em tempo de compilação.

Você organizará seu código em dois arquivos:

  • inspector.go: Crie seu utilitário de inspeção baseado em reflexão.

    Crie uma função InspectStruct(v any) string que use o pacote reflect para examinar qualquer struct passado a ela. Sua função deve retornar um relatório formatado contendo:

    • O nome do tipo da struct
    • O tipo da struct (deve ser "struct")
    • O número de campos
    • Para cada campo: o nome do campo, seu tipo e seu valor atual

    O formato da saída deve ser:

    Type: [TypeName]
    Kind: struct
    Fields: [count]
    - [FieldName] ([FieldType]): [Value]
    - [FieldName] ([FieldType]): [Value]
    ...

    Use reflect.TypeOf() para obter informações sobre o tipo e reflect.ValueOf() para acessar os valores dos campos. Percorra os campos usando NumField(), Field(i) no tipo para obter metadados e Field(i) no valor para obter os valores reais.

  • main.go: Defina structs de exemplo e use seu inspetor.

    Leia um tipo de struct (product ou employee) e seus valores de campo, depois crie a struct apropriada e inspecione-a.

    Para product: Crie uma struct Product com os campos Name (string), Price (float64) e InStock (bool). Leia o nome, o preço e o status do estoque.

    Para employee: Crie uma struct Employee com os campos ID (int), Name (string) e Department (string). Leia o ID, o nome e o departamento.

    Passe a struct criada para InspectStruct e imprima o resultado.

As seguintes entradas serão fornecidas:

  • Linha 1: Tipo da struct (product ou employee)
  • Linhas seguintes: Valores dos campos desse tipo de struct

Por exemplo, dada a entrada:

product
Laptop
999.99
true

Sua saída deve ser:

Type: Product
Kind: struct
Fields: 3
- Name (string): Laptop
- Price (float64): 999.99
- InStock (bool): true

E dada a entrada:

employee
42
Alice Johnson
Engineering

Sua saída deve ser:

Type: Employee
Kind: struct
Fields: 3
- ID (int): 42
- Name (string): Alice Johnson
- Department (string): Engineering

E dada a entrada:

product
Headphones
79.50
false

Sua saída deve ser:

Type: Product
Kind: struct
Fields: 3
- Name (string): Headphones
- Price (float64): 79.5
- InStock (bool): false

Observe como seu inspetor funciona com diferentes tipos de struct sem conhecer sua estrutura antecipadamente. Esse é o poder da reflexão! A mesma função InspectStruct lida dinamicamente com as structs Product e Employee.

Experimente você mesmo

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

// Struct Product com os campos Name, Price e InStock
type Product struct {
	Name    string
	Price   float64
	InStock bool
}

// Struct Employee com os campos ID, Name e Department
type Employee struct {
	ID         int
	Name       string
	Department string
}

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Lê o tipo da struct
	structType, _ := reader.ReadString('\n')
	structType = strings.TrimSpace(structType)

	if structType == "product" {
		// Lê os campos do product
		name, _ := reader.ReadString('\n')
		name = strings.TrimSpace(name)

		priceStr, _ := reader.ReadString('\n')
		priceStr = strings.TrimSpace(priceStr)
		price, _ := strconv.ParseFloat(priceStr, 64)

		inStockStr, _ := reader.ReadString('\n')
		inStockStr = strings.TrimSpace(inStockStr)
		inStock, _ := strconv.ParseBool(inStockStr)

		// TODO: Crie uma struct Product com os valores lidos
		// TODO: Chame InspectStruct com o product e imprima o resultado

	} else if structType == "employee" {
		// Lê os campos do employee
		idStr, _ := reader.ReadString('\n')
		idStr = strings.TrimSpace(idStr)
		id, _ := strconv.Atoi(idStr)

		name, _ := reader.ReadString('\n')
		name = strings.TrimSpace(name)

		department, _ := reader.ReadString('\n')
		department = strings.TrimSpace(department)

		// TODO: Crie uma struct Employee com os valores lidos
		// TODO: Chame InspectStruct com o employee e imprima o resultado

	}
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Compilador de Go online