הפונקציה `init`
חלק מהיחידה לוגיקה וזרימת התוכנית במסלול ה-GO של Coddy. שיעור 56 מתוך 68.
הפונקציה init היא פונקציה מיוחדת ב-Go שרצה אוטומטית כשמייבאים חבילה. בניגוד לפונקציות רגילות, לא קוראים ישירות ל-init — Go מפעילה אותה עבורך במהלך תהליך האתחול של החבילה.
כך מגדירים פונקציית init:
package mypackage
import "fmt"
func init() {
fmt.Println("Package mypackage is being initialized!")
}לפונקציה init יש כמה מאפיינים ייחודיים: היא לא מקבלת פרמטרים, לא מחזירה ערכים, ופועלת לפני שהפונקציה main מתחילה. לכן היא מתאימה במיוחד להגדרת מצב התחלתי, לרישום רכיבים או לביצוע משימות אתחול חד־פעמיות שהחבילה שלך זקוקה להן.
כשמייבאים חבילה שמכילה פונקציית init, אפשר לראות את ההשפעות שלה מיד, גם אם לא משתמשים באף אחת מהפונקציות המיוצאות של החבילה. לכן דפוס הייבוא עם המזהה הריק שלמדת קודם שימושי כל כך — הוא מאפשר להפעיל אתחול של חבילה בלי להשתמש ישירות בקוד שלה.
אתגר
קלצרו מערכת לאתחול חבילות שמדגימה כיצד פונקציות init מופעלות אוטומטית כשמייבאים חבילות. תבנו מערכת רישום שבה חבילות שונות מאתחלות את עצמן ומתעדות את רצף ההפעלה שלהן.
תקבלו שתי קלטות:
- מחרוזת שמכילה הגדרות חבילות בפורמט
"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")
עליכם:
- לנתח את הקלט הראשון באמצעות פיצול לפי פסיקים כדי לקבל את הגדרות החבילות הבודדות
- עבור כל הגדרת חבילה, לפצל לפי נקודתיים כדי לקבל את שם החבילה ואת הודעת האתחול
- ליצור מערך גלובלי בשם
initLogלמעקב אחר הודעות האתחול - ליצור פונקציה בשם
logInitשמקבלת שם חבילה והודעה, ואז מוסיפה למערךinitLogאת ההודעה המעוצבת"[INIT] [package_name]: [message]" - לדמות אתחול חבילות באמצעות קריאה ל-
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, ולכן הן מתאימות במיוחד להגדרה ולאתחול של חבילות.
נסו בעצמכם
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. עבור כל רשומה, פצלו לפי ":" (לכל היותר ל־2 חלקים) כדי לקבל את packageName ואת message
// 3. צרו פונקציה logInit(packageName, message string) שמוסיפה
// את "[INIT] [packageName]: message" לפרוסה הגלובלית initLog
// 4. הציגו את כותרת רצף האתחול ואת כל רשומות יומן האתחול
// 5. הציגו את כותרת הביצוע הראשי ועבדו כל פעולה מתוך mainOps
// - הדפיסו "Executing: <op>" עבור כל פעולה
// - הוסיפו את "[MAIN] Operation: <op>" ל־initLog
// 6. הציגו סיכום ביצוע (מספר החבילות, מספר הפעולות, המספר הכולל של רשומות היומן)
// 7. הצג את היומן המלא ואת הודעת הסיום הסופית
}השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה לוגיקה וזרימת התוכנית
1בקרת זרימה מתקדמת
switch עם `fallthrough`יציאה מלולאות מקוננותהמשך לולאה מסוימתהצהרת `goto`סיכום – שליטה מתקדמת בלולאות4פרויקט: רשימת משימות פשוטה
הגדרת הפרויקטהוספת משימה2מבנים ושיטות
הגדרת שיטות במבניםמקבלי ערךמקבלי מצביעבחירת מקבליםשיטות לעומת פונקציותסיכום — התנהגות המבנים5מפות לעומק
מפות של Structsמצביעים כערכים במפהבדיקה אם מפות הן nilהשוואת מפותסיכום - מונה תדירות מילים8פרויקט: ניהול מלאי פשוט
סקירת הפרויקטבדיקת המלאי3ממשקים (הבסיס)
מהו ממשק?הגדרת ממשקמימוש ממשקשימוש בטיפוסי ממשקממשק ריקבדיקות טיפוסמתג טיפוסיםסיכום – צורות והתנהגויות6קבוצות בסגנון המקובל ב-Go
דפוס הקבוצה ב-Goיצירת קבוצההוספה לקבוצהבדיקת חברות בקבוצההסרה מקבוצהמעבר על איברי קבוצהסיכום – שמות משתמש ייחודיים9חבילות ותחום נראות
מהי חבילה?מיוצא לעומת לא מיוצאיצירת חבילה פשוטהכינוי לחבילההמזהה הריק `_`הפונקציה `init`סיכום – בניית כלי עזרתרגלו בעצמכם: קומפיילר Go אונליין