Menu
Coddy logo textTech

העברה לפי ערך לעומת לפי הפניה

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

Go היא שפה שבה מעבירים לפי ערך. כשמעבירים משתנה לפונקציה, Go יוצרת עותק של הערך הזה. פירוש הדבר הוא ששינויים בתוך הפונקציה אינם משפיעים על המשתנה המקורי.

func double(n int) {
    n = n * 2
}

func main() {
    x := 10
    double(x)
    fmt.Println(x)  // 10 (ללא שינוי)
}

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

type Person struct {
    Name string
    Age  int
}

func birthday(p Person) {
    p.Age++
}

func main() {
    alice := Person{Name: "Alice", Age: 30}
    birthday(alice)
    fmt.Println(alice.Age)  // 30 (ללא שינוי)
}

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

func birthday(p *Person) {
    p.Age++
}

func main() {
    alice := Person{Name: "Alice", Age: 30}
    birthday(&alice)
    fmt.Println(alice.Age)  // 31 (שונה!)
}

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

challenge icon

אתגר

קל

בואו נבנה מערכת עגלת קניות שמדגימה את ההבדל בין העברת מבנים לפי ערך לבין העברתם באמצעות מצביע. תוכלו לראות במו עיניכם שרק פרמטרים של מצביע יכולים לשנות את הנתונים המקוריים.

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

  • cart.go: הגדירו מבנה CartItem עם השדות Name (מחרוזת), Price (float64) ו-Quantity (int). צרו שתי פונקציות שמנסות לעדכן את הכמות:
    • UpdateQuantityByValue מקבלת CartItem (לפי ערך) וכמות חדשה, ואז קובעת את הכמות של הפריט לערך החדש
    • UpdateQuantityByPointer מקבלת *CartItem (מצביע) וכמות חדשה, ואז קובעת את הכמות של הפריט לערך החדש
    צרו גם מתודה Total עבור CartItem, שמחזירה את המחיר כפול הכמות.
  • main.go: קראו את פרטי הפריט מהקלט, צרו CartItem, ואז הדגימו את שתי דרכי העדכון. תחילה נסו לעדכן באמצעות פונקציית הערך והציגו את התוצאה, ואז עדכנו באמצעות פונקציית המצביע והציגו שוב את התוצאה.

הקלט הבא יסופק:

  • שורה 1: שם הפריט
  • שורה 2: מחיר (מספר עשרוני)
  • שורה 3: כמות התחלתית (מספר שלם)
  • שורה 4: הכמות החדשה שיש לקבוע (מספר שלם)

מבנה הפלט:

Initial: [Name] x[Quantity] = $[Total]
After value update: [Name] x[Quantity] = $[Total]
After pointer update: [Name] x[Quantity] = $[Total]

לדוגמה, עבור Laptop, 999.99, 1 ו-3, הפלט שלכם אמור להיות:

Initial: Laptop x1 = $999.99
After value update: Laptop x1 = $999.99
After pointer update: Laptop x3 = $2999.97

שימו לב שהכמות נשארת 1 לאחר העדכון לפי ערך (הפונקציה שינתה עותק), אך משתנה ל-3 לאחר העדכון באמצעות מצביע (הפונקציה שינתה את המקור). עצבו את הסכומים עם שתי ספרות אחרי הנקודה העשרונית.

נסו בעצמכם

package main

import (
	"fmt"
)

func main() {
	// קראו את הקלט
	var name string
	var price float64
	var initialQty, newQty int

	fmt.Scanln(&name)
	fmt.Scanln(&price)
	fmt.Scanln(&initialQty)
	fmt.Scanln(&newQty)

	// TODO: צרו CartItem עם ערכי הקלט

	// TODO: הדפיסו את המצב ההתחלתי באמצעות הפורמט:
	// fmt.Printf("Initial: %s x%d = $%.2f\n", ...)

	// TODO: נסו לעדכן את הכמות באמצעות UpdateQuantityByValue
	// לאחר מכן הדפיסו את התוצאה (שימו לב שהכמות לא תשתנה)

	// TODO: עדכנו את הכמות באמצעות UpdateQuantityByPointer
	// לאחר מכן הדפיסו את התוצאה (שימו לב שהכמות תשתנה)
}
quiz iconבחנו את עצמכם

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

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

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