Menu
Coddy logo textTech

Wprowadzenie do typów generycznych

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

Przed Go 1.18 pisanie wielokrotnego użytku kodu dla różnych typów oznaczało albo powielanie funkcji, albo używanie pustego interfejsu any z asercjami typów. Typy generyczne rozwiązują ten problem, pozwalając pisać funkcje i typy działające z wieloma typami przy zachowaniu pełnego bezpieczeństwa typów.

Rozważ znalezienie najmniejszej wartości w wycinku. Bez typów generycznych potrzebne byłyby osobne funkcje dla każdego typu:

func MinInt(values []int) int {
    min := values[0]
    for _, v := range values {
        if v < min {
            min = v
        }
    }
    return min
}

func MinFloat64(values []float64) float64 {
    min := values[0]
    for _, v := range values {
        if v < min {
            min = v
        }
    }
    return min
}

Dzięki typom generycznym zapisujesz logikę raz, używając parametru typu w nawiasach kwadratowych:

func Min[T int | float64](values []T) T {
    min := values[0]
    for _, v := range values {
        if v < min {
            min = v
        }
    }
    return min
}

[T int | float64] deklaruje parametr typu T, który może być typu int lub float64. Teraz możesz wywołać Min([]int{3, 1, 2}) lub Min([]float64{3.5, 1.2}) za pomocą tej samej funkcji. Kompilator sprawdza typy podczas kompilacji, dzięki czemu zyskujesz bezpieczeństwo bez narzutu w czasie działania.

W kolejnych lekcjach szczegółowo omówimy parametry typów, ograniczenia i struktury generyczne.

challenge icon

Wyzwanie

Łatwy

Stwórzmy analizator wyników, który obsługuje zarówno wyniki całkowite, jak i zmiennoprzecinkowe, wykorzystując typy generyczne! Utworzysz jedną funkcję generyczną, która znajdzie największą wartość w wycinku, eliminując potrzebę powielania kodu dla różnych typów liczbowych.

Rozmieścisz kod w dwóch plikach:

  • analyzer.go: Zdefiniuj funkcję generyczną do analizy.

    Utwórz funkcję generyczną Max[T int | float64](values []T) T, która znajduje i zwraca największą wartość w wycinku. Dzięki parametrowi typu T funkcja powinna działać zarówno z typem int, jak i float64.

    Utwórz także funkcję generyczną Sum[T int | float64](values []T) T, która oblicza i zwraca sumę wszystkich wartości w wycinku.

  • main.go: Wczytaj dane wejściowe i zaprezentuj działanie funkcji generycznych z różnymi typami.

    Wczytaj oznaczenie typu (int lub float), a następnie wczytaj liczbę wartości i podaną liczbę wartości. Parsuj wartości zgodnie z typem, wywołaj zarówno Max, jak i Sum z odpowiednim typem, a następnie wypisz wyniki.

    Dla danych wejściowych typu całkowitego wypisz:

    Max (int): [value]
    Sum (int): [value]

    Dla danych wejściowych typu zmiennoprzecinkowego wypisz wartości z jednym miejscem po przecinku:

    Max (float): [value]
    Sum (float): [value]

Otrzymasz następujące dane wejściowe:

  • Wiersz 1: Oznaczenie typu (int lub float)
  • Wiersz 2: Liczba wartości (liczba całkowita)
  • Kolejne wiersze: Jedna wartość w każdym wierszu

Na przykład, dla danych:

int
4
15
8
23
11

Wynik powinien być następujący:

Max (int): 23
Sum (int): 57

A dla danych:

float
3
4.5
9.2
6.8

Wynik powinien być następujący:

Max (float): 9.2
Sum (float): 20.5

Zwróć uwagę, że te same funkcje generyczne obsługują zarówno dane całkowite, jak i zmiennoprzecinkowe: parametr typu [T int | float64] pozwala kompilatorowi generować bezpieczny typowo kod dla każdego użycia, podczas gdy logikę zapisujesz tylko raz.

Spróbuj swoich sił

package main

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

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

	// Odczytaj wskaźnik typu
	typeStr, _ := reader.ReadString('\n')
	typeStr = strings.TrimSpace(typeStr)

	// Odczytaj liczbę elementów
	countStr, _ := reader.ReadString('\n')
	count, _ := strconv.Atoi(strings.TrimSpace(countStr))

	if typeStr == "int" {
		// Odczytaj wartości całkowite
		values := make([]int, count)
		for i := 0; i < count; i++ {
			line, _ := reader.ReadString('\n')
			values[i], _ = strconv.Atoi(strings.TrimSpace(line))
		}

		// TODO: Wywołaj Max i Sum, przekazując wycinek liczb całkowitych
		// TODO: Wypisz wyniki w formacie "Max (int): [value]" i "Sum (int): [value]"

	} else if typeStr == "float" {
		// Odczytaj wartości zmiennoprzecinkowe
		values := make([]float64, count)
		for i := 0; i < count; i++ {
			line, _ := reader.ReadString('\n')
			values[i], _ = strconv.ParseFloat(strings.TrimSpace(line), 64)
		}

		// TODO: Wywołaj Max i Sum, przekazując wycinek wartości float64
		// TODO: Wypisz wyniki z jednym miejscem po przecinku w formacie "Max (float): [value]" i "Sum (float): [value]"
	}
}
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