Menu
Coddy logo textTech

מבוא ל־Generics

חלק מהיחידה תכנות מונחה עצמים במסלול ה-GO של Coddy. שיעור 67 מתוך 107.

לפני Go 1.18, כתיבת קוד לשימוש חוזר עבור טיפוסים שונים חייבה שכפול של פונקציות או שימוש בממשק הריק any עם המרות טיפוס. גנריות פותרות את הבעיה הזאת בכך שהן מאפשרות לכתוב פונקציות וטיפוסים שעובדים עם כמה טיפוסים, תוך שמירה על בטיחות טיפוסים מלאה.

נניח שצריך למצוא את הערך המינימלי בפרוסה. ללא גנריות, תצטרכו פונקציות נפרדות לכל טיפוס:

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
}

עם טיפוסים גנריים, כותבים את הלוגיקה פעם אחת באמצעות פרמטר טיפוס בסוגריים מרובעים:

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] מגדירה פרמטר טיפוס T שיכול להיות int או float64. עכשיו אפשר לקרוא לאותה פונקציה באמצעות Min([]int{3, 1, 2}) או Min([]float64{3.5, 1.2}). המהדר בודק טיפוסים בזמן הקומפילציה, כך שמקבלים בטיחות ללא תקורה בזמן ריצה.

בשיעורים הבאים נחקור לעומק פרמטרים של טיפוסים, אילוצים ומבנים גנריים.

challenge icon

אתגר

קל

בואו נבנה מנתח ציונים שעובד גם עם ציונים של מספרים שלמים וגם עם ציונים של מספרים בנקודה צפה באמצעות גנריות! תיצרו פונקציה גנרית אחת שתוכל למצוא את הערך המרבי בפרוסה, וכך לא יהיה צורך בקוד כפול עבור סוגים מספריים שונים.

תארגנו את הקוד שלכם בשני קבצים:

  • analyzer.go: הגדירו את פונקציית הניתוח הגנרית שלכם.

    צרו פונקציה גנרית Max[T int | float64](values []T) T שמוצאת ומחזירה את הערך המרבי בפרוסה. הפונקציה צריכה לעבוד עם שני הסוגים int ו-float64 באמצעות פרמטר הטיפוס T.

    צרו גם פונקציה גנרית Sum[T int | float64](values []T) T שמחשבת ומחזירה את סכום כל הערכים בפרוסה.

  • main.go: קראו את הקלט והדגימו את הפונקציות הגנריות שלכם עם טיפוסים שונים.

    קראו מציין טיפוס (int או float), אחריו קראו את הכמות ואז את מספר הערכים הזה. נתחו את הערכים בהתאם לטיפוס, קראו גם ל-Max וגם ל-Sum עם הטיפוס המתאים, והדפיסו את התוצאות.

    עבור קלט של מספרים שלמים, הדפיסו:

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

    עבור קלט של מספרים בנקודה צפה, הדפיסו ספרה אחת אחרי הנקודה העשרונית:

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

הקלט יינתן בפורמט הבא:

  • שורה 1: מציין טיפוס (int או float)
  • שורה 2: מספר הערכים (מספר שלם)
  • השורות הבאות: ערך אחד בכל שורה

לדוגמה, בהינתן:

int
4
15
8
23
11

הפלט שלכם צריך להיות:

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

ובהינתן:

float
3
4.5
9.2
6.8

הפלט שלכם צריך להיות:

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

שימו לב כיצד אותן פונקציות גנריות מטפלות גם בנתונים מסוג מספר שלם וגם בנתונים מסוג מספר בנקודה צפה: פרמטר הטיפוס [T int | float64] מאפשר למהדר ליצור קוד בטוח מבחינת טיפוסים עבור כל שימוש, בזמן שאתם כותבים את הלוגיקה פעם אחת בלבד.

נסו בעצמכם

package main

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

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

	// קרא את מציין הסוג
	typeStr, _ := reader.ReadString('\n')
	typeStr = strings.TrimSpace(typeStr)

	// קרא את הכמות
	countStr, _ := reader.ReadString('\n')
	count, _ := strconv.Atoi(strings.TrimSpace(countStr))

	if typeStr == "int" {
		// קרא ערכים של מספרים שלמים
		values := make([]int, count)
		for i := 0; i < count; i++ {
			line, _ := reader.ReadString('\n')
			values[i], _ = strconv.Atoi(strings.TrimSpace(line))
		}

		// TODO: קרא ל-Max ול-Sum עם פרוסה של מספרים שלמים
		// TODO: הדפס את התוצאות בפורמט "Max (int): [value]" ו-"Sum (int): [value]"

	} else if typeStr == "float" {
		// קרא ערכים של מספרים עשרוניים
		values := make([]float64, count)
		for i := 0; i < count; i++ {
			line, _ := reader.ReadString('\n')
			values[i], _ = strconv.ParseFloat(strings.TrimSpace(line), 64)
		}

		// TODO: קרא ל-Max ול-Sum עם פרוסה של float64
		// TODO: הדפס את התוצאות עם ספרה אחת אחרי הנקודה העשרונית בפורמט "Max (float): [value]" ו-"Sum (float): [value]"
	}
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר Go אונליין