Menu
Coddy logo textTech

Podstawy refleksji

Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 83 z 107.

Refleksja pozwala programowi analizować i modyfikować własną strukturę w czasie wykonywania. Pakiet reflect języka Go zapewnia tę możliwość, umożliwiając sprawdzanie typów, odczytywanie pól struktur i dynamiczne wywoływanie metod.

Dwa podstawowe typy w refleksji to reflect.Type i reflect.Value. Uzyskujesz je za pomocą reflect.TypeOf() i 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

Możesz iterować po polach struktury, aby sprawdzić ich nazwy, typy i wartości:

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

Refleksja jest potężna, ale wiąże się z kompromisami: omija kontrolę typów podczas kompilacji, działa wolniej niż bezpośredni dostęp i utrudnia zrozumienie kodu. Używaj jej oszczędnie do zadań takich jak serializacja JSON, mapowanie ORM czy tworzenie uniwersalnych narzędzi, gdy typ nie jest znany podczas kompilacji.

challenge icon

Wyzwanie

Łatwy

Zbudujmy inspektor struktur, który używa refleksji do analizowania dowolnej struktury i opisywania jej budowy! To praktyczne zastosowanie refleksji: tworzenie narzędzi działających z typami nieznanymi w czasie kompilacji.

Podzielisz kod na dwa pliki:

  • inspector.go: Utwórz narzędzie inspekcji oparte na refleksji.

    Zbuduj funkcję InspectStruct(v any) string, która używa pakietu reflect do analizowania przekazanej jej dowolnej struktury. Twoja funkcja powinna zwracać sformatowany raport zawierający:

    • Nazwę typu struktury
    • Rodzaj struktury (powinien mieć wartość "struct")
    • Liczbę pól
    • Dla każdego pola: nazwę pola, jego typ i bieżącą wartość

    Format wyjściowy powinien wyglądać tak:

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

    Użyj reflect.TypeOf(), aby uzyskać informacje o typie, i reflect.ValueOf(), aby uzyskać dostęp do wartości pól. Przejdź przez pola, używając NumField(), Field(i) dla typu, aby uzyskać metadane, oraz Field(i) dla wartości, aby uzyskać rzeczywiste wartości.

  • main.go: Zdefiniuj przykładowe struktury i użyj swojego inspektora.

    Wczytaj typ struktury (product lub employee) oraz wartości jej pól, a następnie utwórz odpowiednią strukturę i ją przeanalizuj.

    Dla product: Utwórz strukturę Product z polami Name (string), Price (float64) i InStock (bool). Wczytaj nazwę, cenę i stan magazynowy.

    Dla employee: Utwórz strukturę Employee z polami ID (int), Name (string) i Department (string). Wczytaj identyfikator, imię i dział.

    Przekaż utworzoną strukturę do InspectStruct i wypisz wynik.

Dane wejściowe będą miały następującą postać:

  • Wiersz 1: Typ struktury (product lub employee)
  • Kolejne wiersze: Wartości pól tej struktury

Na przykład dla danych:

product
Laptop
999.99
true

Wynik powinien wyglądać tak:

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

A dla danych:

employee
42
Alice Johnson
Engineering

Wynik powinien wyglądać tak:

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

A dla danych:

product
Headphones
79.50
false

Wynik powinien wyglądać tak:

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

Zwróć uwagę, że Twój inspektor obsługuje różne typy struktur, nie znając wcześniej ich budowy. Na tym polega potęga refleksji! Ta sama funkcja InspectStruct dynamicznie obsługuje zarówno struktury Product, jak i Employee.

Spróbuj swoich sił

package main

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

// Struktura Product z polami Name, Price i InStock
type Product struct {
	Name    string
	Price   float64
	InStock bool
}

// Struktura Employee z polami ID, Name i Department
type Employee struct {
	ID         int
	Name       string
	Department string
}

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

	// Odczytaj typ struktury
	structType, _ := reader.ReadString('\n')
	structType = strings.TrimSpace(structType)

	if structType == "product" {
		// Odczytaj pola produktu
		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: Utwórz strukturę Product z odczytanymi wartościami
		// TODO: Wywołaj InspectStruct dla produktu i wypisz wynik

	} else if structType == "employee" {
		// Odczytaj pola pracownika
		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: Utwórz strukturę Employee z odczytanymi wartościami
		// TODO: Wywołaj InspectStruct dla pracownika i wypisz wynik

	}
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Go online