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

الواجهة الفارغة (any)

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

تُعد الواجهة الفارغة واجهةً لا تحتوي على أي دوال (methods). وبما أن كل نوع في لغة Go يمتلك على الأقل صفر من الدوال، فإن كل نوع يحقق تلقائياً شروط الواجهة الفارغة. وهذا يجعلها قادرة على استيعاب قيم من أي نوع.

var anything interface{}

anything = 42
anything = "hello"
anything = true
anything = []int{1, 2, 3}

بدءاً من الإصدار Go 1.18، تم تقديم الكلمة المفتاحية any كاسم مستعار لـ interface{}. إنهما قابلان للتبادل تماماً، لكن any أسهل في القراءة.

var value any = "Go is awesome"

تُعد الواجهة الفارغة (empty interface) مفيدة عندما تحتاج إلى التعامل مع قيم من أنواع غير معروفة أو متنوعة. تستخدمها دوال مثل fmt.Println لقبول وسائط من أي نوع:

func PrintAnything(v any) {
    fmt.Println("Value:", v)
}

func main() {
    PrintAnything(100)
    PrintAnything("text")
    PrintAnything(3.14)
}

ومع ذلك، هناك مقايضة. فعندما يتم تخزين قيمة في واجهة فارغة (empty interface)، ستفقد إمكانية الوصول إلى معلومات النوع الخاصة بها.

لا يمكنك استدعاء الأساليب أو الوصول إلى الحقول مباشرة دون استخراج النوع الأساسي أولاً. ستغطي الدروس القادمة كيفية استرداد النوع الملموس من واجهة فارغة باستخدام تأكيدات النوع (type assertions) وتبديلات النوع (type switches).

challenge icon

التحدي

سهل

لنقم ببناء حاوية تخزين مرنة يمكنها الاحتفاظ بقيم من أي نوع باستخدام الواجهة الفارغة (empty interface). ستقوم بإنشاء صندوق بسيط يوضح كيف يسمح لك النوع any بتخزين أنواع مختلفة في نفس الهيكل.

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

  • box.go: قم بتعريف هيكل Box مع حقل واحد Content من نوع any. أنشئ دالة منشئة NewBox تقبل قيمة من أي نوع وتعيد مؤشراً (pointer) إلى Box يحتوي على تلك القيمة. أضف تابعاً Describe يعيد سلسلة نصية توضح ما هو مخزن في الصندوق.
  • main.go: اقرأ قيماً مختلفة من المدخلات، وأنشئ صناديق تحتوي على عدد صحيح، وسلسلة نصية، وقيمة منطقية، ثم اطبع وصف كل صندوق لإظهار كيف يمكن لنفس نوع Box أن يحمل قيماً مختلفة تماماً.

سيتم توفير المدخلات التالية:

  • السطر 1: قيمة عدد صحيح (integer)
  • السطر 2: قيمة سلسلة نصية (string)
  • السطر 3: قيمة منطقية (boolean) (true أو false)

يجب أن يعيد التابع Describe سلسلة نصية بهذا التنسيق:

Box contains: [value]

على سبيل المثال، إذا كانت المدخلات 42، و hello، و true، يجب أن يكون مخرجك:

Box contains: 42
Box contains: hello
Box contains: true

الفكرة الأساسية هنا هي أن هيكل Box الواحد الخاص بك يمكنه تخزين عدد صحيح، أو سلسلة نصية، أو قيمة منطقية — كل ذلك لأن النوع any يقبل قيماً من أي نوع. كل صندوق يحمل شيئاً مختلفاً، ومع ذلك فجميعهم من نفس النوع Box.

ورقة مرجعية

تُعد الواجهة الفارغة (interface{}) واجهة لا تحتوي على أي دوال (methods). وبما أن كل نوع في لغة Go يحتوي على الأقل على صفر من الدوال، فإن كل نوع يحقق تلقائياً شروط الواجهة الفارغة، مما يجعلها قادرة على حمل قيم من أي نوع.

var anything interface{}

anything = 42
anything = "hello"
anything = true
anything = []int{1, 2, 3}

بدءاً من الإصدار Go 1.18، تم تقديم الكلمة المفتاحية any كاسم مستعار (alias) لـ interface{}. إنهما قابلان للتبادل تماماً، لكن any أكثر وضوحاً في القراءة:

var value any = "Go is awesome"

الواجهة الفارغة مفيدة للتعامل مع قيم من أنواع غير معروفة أو متنوعة. يمكن للدوال قبول وسائط من أي نوع:

func PrintAnything(v any) {
    fmt.Println("Value:", v)
}

func main() {
    PrintAnything(100)
    PrintAnything("text")
    PrintAnything(3.14)
}

المقايضة (Tradeoff): عندما يتم تخزين قيمة في واجهة فارغة، فإنك تفقد الوصول إلى معلومات النوع المحددة الخاصة بها. لا يمكنك استدعاء الدوال أو الوصول إلى الحقول مباشرة دون استخراج النوع الأساسي أولاً باستخدام تأكيدات النوع (type assertions) أو مفاتيح النوع (type switches).

جرّب بنفسك

package main

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

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

	// قراءة قيمة integer
	line1, _ := reader.ReadString('\n')
	intVal, _ := strconv.Atoi(strings.TrimSpace(line1))

	// قراءة قيمة string
	line2, _ := reader.ReadString('\n')
	strVal := strings.TrimSpace(line2)

	// قراءة قيمة boolean
	line3, _ := reader.ReadString('\n')
	boolVal, _ := strconv.ParseBool(strings.TrimSpace(line3))

	// TODO: إنشاء صناديق لكل قيمة باستخدام NewBox
	// TODO: طباعة وصف كل صندوق باستخدام التابع Describe

	// استخدم المتغيرات لتجنب أخطاء التجميع (قم بإزالة هذه الأسطر عند التنفيذ)
	_ = intVal
	_ = strVal
	_ = boolVal

	// مثال على تنسيق المخرجات:
	// fmt.Println(box.Describe())
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming