Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

مقدمة في الأنواع العامة

جزء من قسم Object Oriented Programming في رحلة GO على Coddy — الدرس 67 من 107.

قبل إصدار Go 1.18، كانت كتابة كود قابل لإعادة الاستخدام لأنواع مختلفة تعني إما تكرار الدوال أو استخدام الواجهة الفارغة any مع تأكيدات النوع (type assertions). تحل الـ Generics هذه المشكلة من خلال السماح لك بكتابة دوال وأنواع تعمل مع أنواع متعددة مع الحفاظ على سلامة النوع (type safety) الكاملة.

فكر في العثور على القيمة الصغرى في شريحة (slice). بدون القوالب العامة (generics)، ستحتاج إلى دوال منفصلة لكل نوع:

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
}

مع الـ generics، تكتب المنطق مرة واحدة باستخدام معامل نوع (type parameter) داخل أقواس مربعة:

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}) باستخدام نفس الدالة. يتحقق المترجم من الأنواع في وقت الترجمة، لذا تحصل على الأمان دون أعباء إضافية في وقت التشغيل.

في الدروس القادمة، سنستكشف بارامترات النوع (type parameters)، والقيود (constraints)، والهياكل العامة (generic structs) بالتفصيل.

challenge icon

التحدي

سهل

لنقم ببناء محلل درجات يعمل مع كل من الدرجات الصحيحة والكسرية باستخدام القوالب العامة (generics)! ستقوم بإنشاء دالة عامة واحدة يمكنها العثور على القيمة القصوى في شريحة (slice)، مما يلغي الحاجة إلى تكرار الكود لأنواع رقمية مختلفة.

ستقوم بتنظيم الكود الخاص بك عبر ملفين:

  • 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 بالنوع المناسب، واطبع النتائج.

    بالنسبة لمدخلات الأعداد الصحيحة (integer)، اطبع:

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

    بالنسبة لمدخلات الأعداد الكسرية (float)، اطبع بمنزلة عشرية واحدة:

    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] للمترجم بإنشاء كود آمن النوع (type-safe) لكل استخدام بينما تكتب أنت المنطق مرة واحدة فقط.

جرّب بنفسك

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" {
		// قراءة قيم الأعداد الصحيحة (integer)
		values := make([]int, count)
		for i := 0; i < count; i++ {
			line, _ := reader.ReadString('\n')
			values[i], _ = strconv.Atoi(strings.TrimSpace(line))
		}

		// TODO: استدعاء Max و Sum مع شريحة (slice) من نوع integer
		// TODO: طباعة النتائج بالتنسيق "Max (int): [value]" و "Sum (int): [value]"

	} else if typeStr == "float" {
		// قراءة قيم الأعداد العشرية (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 مع شريحة (slice) من نوع float64
		// TODO: طباعة النتائج مع منزلة عشرية واحدة بالتنسيق "Max (float): [value]" و "Sum (float): [value]"
	}
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming