دالة `init`
جزء من قسم Logic & Flow في رحلة GO على Coddy — الدرس 56 من 68.
دالة init هي دالة خاصة في Go تعمل تلقائياً عند استيراد حزمة (package). على عكس الدوال العادية، لا تقوم باستدعاء init بشكل مباشر - تقوم Go بتنفيذها نيابة عنك أثناء عملية تهيئة الحزمة.
إليك كيفية تعريف دالة init:
package mypackage
import "fmt"
func init() {
fmt.Println("Package mypackage is being initialized!")
}تتميز وظيفة init ببعض الخصائص الفريدة: فهي لا تأخذ أي معاملات، ولا تعيد أي قيم، وتعمل قبل بدء وظيفة main. وهذا يجعلها مثالية لإعداد الحالة الأولية، أو تسجيل المكونات، أو أداء مهام الإعداد التي تتم لمرة واحدة والتي تحتاجها الحزمة الخاصة بك.
عندما تقوم باستيراد حزمة تحتوي على دالة init، سترى تأثيراتها على الفور، حتى لو لم تستخدم أيًا من الدوال المصدرة للحزمة. هذا هو السبب في أن نمط استيراد المعرف الفارغ (blank identifier import pattern) الذي تعلمته سابقًا مفيد جدًا - فهو يسمح لك بتشغيل تهيئة الحزمة دون استخدام الكود الخاص بها بشكل مباشر.
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
التحدي
سهلقم بإنشاء نظام تهيئة حزم (package initialization system) يوضح كيفية تنفيذ دوال init تلقائياً عند استيراد الحزم. ستقوم ببناء نظام تسجيل (logging system) حيث تقوم الحزم المختلفة بتهيئة نفسها وتتبع تسلسل بدء التشغيل الخاص بها.
ستتلقى مدخلين:
- سلسلة نصية تحتوي على تعريفات الحزم بتنسيق
"package1:message1,package2:message2,package3:message3"(على سبيل المثال،"database:Database connection pool initialized,cache:Cache system ready,logger:Logging system started") - سلسلة نصية تحتوي على عمليات البرنامج الرئيسي بتنسيق
"operation1,operation2,operation3"(على سبيل المثال،"start_server,process_requests,shutdown")
مهمتك هي:
- تحليل المدخل الأول عن طريق تقسيمه عند الفواصل للحصول على تعريفات الحزم الفردية
- لكل تعريف حزمة، قم بالتقسيم عند النقطتين الرأسيتين للحصول على اسم الحزمة ورسالة التهيئة
- إنشاء شريحة عالمية (global slice) تسمى
initLogلتتبع رسائل التهيئة - إنشاء دالة تسمى
logInitتأخذ اسم الحزمة والرسالة، ثم تضيف الرسالة المنسقة"[INIT] [package_name]: [message]"إلى شريحةinitLog - محاكاة تهيئة الحزمة عن طريق استدعاء
logInitلكل حزمة بالترتيب الذي تظهر به في المدخلات - عرض رأس تسلسل التهيئة:
"=== PACKAGE INITIALIZATION SEQUENCE ===" - طباعة كل رسالة تهيئة من شريحة
initLog - عرض رأس البرنامج الرئيسي:
"=== MAIN PROGRAM EXECUTION ===" - طباعة:
"All packages initialized successfully" - تحليل المدخل الثاني عن طريق تقسيمه عند الفواصل للحصول على العمليات الفردية
- لكل عملية في البرنامج الرئيسي:
- طباعة:
"Executing: [operation]" - إضافة رسالة إلى السجل:
"[MAIN] Operation: [operation]" - عرض ملخص التنفيذ:
"=== EXECUTION SUMMARY ===""Packages initialized: [number_of_packages]""Main operations executed: [number_of_operations]""Total log entries: [total_number_of_log_entries]"- عرض السجل الكامل:
"=== COMPLETE EXECUTION LOG ==="- طباعة كل إدخال من السجل الكامل (رسائل التهيئة وعمليات البرنامج الرئيسي معاً)
- عرض الرسالة النهائية:
"Program execution completed - all init functions ran before main"
استخدم حزمة strings لتقسيم سلاسل المدخلات وحزمة fmt للمخرجات المنسقة. يوضح هذا التحدي كيفية تنفيذ دوال init تلقائياً أثناء استيراد الحزمة وتشغيلها دائماً قبل دالة main، مما يجعلها مثالية لمهام إعداد وتهيئة الحزم.
ورقة مرجعية
دالة init هي دالة خاصة في لغة Go تعمل تلقائياً عند استيراد الحزمة:
package mypackage
import "fmt"
func init() {
fmt.Println("Package mypackage is being initialized!")
}الخصائص الرئيسية لدوال init:
- لا تأخذ أي معاملات ولا تعيد أي قيم
- تعمل تلقائياً أثناء تهيئة الحزمة
- تُنفذ قبل بدء دالة
main - مثالية لإعداد الحالة الأولية ومهام الإعداد التي تُنفذ لمرة واحدة
- يتم استدعاؤها حتى مع عمليات الاستيراد باستخدام المعرف الفارغ (blank identifier)
جرّب بنفسك
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
// شريحة عالمية لتتبع رسائل التهيئة
var initLog []string
func main() {
reader := bufio.NewReader(os.Stdin)
// قراءة المدخلات (bufio يتعامل مع الأسطر التي تحتوي على مسافات بشكل صحيح)
packageDefs, _ := reader.ReadString('\n')
packageDefs = strings.TrimRight(packageDefs, "\r\n")
mainOps, _ := reader.ReadString('\n')
mainOps = strings.TrimRight(mainOps, "\r\n")
// TODO: اكتب الكود الخاص بك أدناه
// 1. قم بتحليل packageDefs عن طريق التقسيم عند "," للحصول على إدخالات الحزم الفردية
// 2. لكل إدخال، قم بالتقسيم عند ":" (بحد أقصى جزأين) للحصول على packageName و message
// 3. قم بإنشاء دالة logInit(packageName, message string) التي تضيف
// "[INIT] [packageName]: message" إلى شريحة initLog العالمية
// 4. عرض رأس تسلسل التهيئة وجميع إدخالات سجل التهيئة
// 5. عرض رأس التنفيذ الرئيسي ومعالجة كل عملية من mainOps
// - طباعة "Executing: <op>" لكل عملية
// - إضافة "[MAIN] Operation: <op>" إلى initLog
// 6. عرض ملخص التنفيذ (عدد الحزم، عدد العمليات، إجمالي إدخالات السجل)
// 7. عرض السجل الكامل ورسالة الإكمال النهائية
}يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Logic & Flow
1تدفق التحكم المتقدم
جملة Switch مع `fallthrough`الخروج من الحلقات المتداخلةالاستمرار في حلقة محددةجملة `goto`ملخص - التحكم المتقدم في الحلقات2الـ Structs والميثودز (Methods)
تعريف الـ Methods على الـ Structsالـ Value Receiversالـ Pointer Receiversاختيار الـ Receiversالـ Methods مقابل الـ Functionsملخص - سلوك الـ Struct5تعمق في الـ Maps
Maps من نوع Structsالـ Pointers كقيم في الـ Mapsالتحقق من الـ Nil Mapsمقارنة الـ Mapsمراجعة - عداد تكرار الكلمات3الواجهات (الأساسيات)
ما هي الواجهة؟تعريف الواجهةتطبيق الواجهةاستخدام أنواع الواجهاتالواجهة الفارغةتأكيدات النوع (Type Assertions)تبديل النوع (Type Switch)ملخص - الأشكال والسلوكيات