איך להשתמש במשתנים וקבועים בגו

משתנים הם מושג תכנותי חשוב לשליטה. הם סמלים שמייצגים ערך שאתה משתמש בו בתוכנית.

מדריך זה יכסה כמה יסודות בסיסיים של משתנים ושיטות עבודה טובות ביותר לשימושם בתוכניות Go שתיצר.

הבנת משתנים

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

אנו יכולים לחשוב על משתנה כמיתוג שיש עליו שם, שאתה קושר לערך.

נניח שיש לנו מספר שלם, 1032049348, ואנו רוצים לאחסן אותו במשתנה במקום להקליד שוב ושוב את המספר הארוך. כדי להשיג זאת, אנו יכולים להשתמש בשם שקל לזכור, כמו המשתנה i. כדי לאחסן ערך במשתנה, אנו משתמשים בתחביר הבא:

i := 1032049348

אנו יכולים לחשוב על המשתנה הזה כמיתוג שמקושר לערך.

המיתוג כולל את שם המשתנה i ומקושר לערך השלם 1032049348.

הביטוי i := 1032049348 הוא משפט הצהרה והקצאה המורכב ממספר חלקים:

  • שם המשתנה (i)
  • הקצאת הצהרת משתנה קצרה (:=)
  • אחד מה שמורך לקבלת השמים (1032049348)
  • מטבעת מציאת המספרים שניתן לה במחלקה הבאה.

אז נראה מאחרים כמה מתבנים המשפט שמותח את המשפט של המשפט האחרי.

מחלקה זו משפט שמותח את המשפט של המשפט האחרי, ואז משפט זה משפט שמותח את המשפט של המשפט האחרי.

אחד מה שמורך לקבלת השמים (1032049348)מחלקה זו משפט שמותח את המשפט של המשפט האחרי.

אחד מה שמורך לקבלת השמים (1032049348)

package main

import "fmt"

func main() {
	i := 1032049348
	fmt.Println(i)
}
Output
1032049348

מחלקה זו משפט שמותח את המשפט של המשפט האחרי.

fmt.Println(i - 813)
Output
1032048535

אחד מה שמורך לקבלת השמים (1032049348)

מחלקה זו משפט שמותח את המשפט של המשפט האחרי.

x := 76 + 145

אחד מה שמורך לקבלת השמים (1032049348)

מחלקה זו משפט שמותח את המשפט של המשפט האחרי.

package main

import "fmt"

func main() {
	x := 76 + 145
	fmt.Println(x)
}
Output
221

Go החזיר את הערך 221 מכיוון שהמשתנה x הוגדר שווה לסכום של 76 ו-145.

משתנים יכולים לייצג כל סוג נתונים, לא רק מספרים שלמים:

s := "Hello, World!"
f := 45.06
b := 5 > 9 // ערך בוליאני יחזיר או נכון או לא נכון
array := [4]string{"item_1", "item_2", "item_3", "item_4"}
slice := []string{"one", "two", "three"}
m := map[string]string{"letter": "g", "number": "seven", "symbol": "&"}

אם תדפיס כל אחד מהמשתנים האלה, Go יחזיר מה שהמשתנה שווה אליו. בואו נעבוד עם הצהרת השמה עבור סוג הנתונים slice של מחרוזות:

package main

import "fmt"

func main() {
	slice := []string{"one", "two", "three"}
	fmt.Println(slice)
}
Output
[one two three]

הקצינו את הערך של []string{"one", "two", "three"} למשתנה slice, ואז השתמשנו בפונקציה fmt.Println כדי להדפיס את הערך הזה על ידי קריאה ל-slice.

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

הכרזה על משתנים

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

אנו יכולים להכריז על משתנה בשם i מסוג נתונים int ללא אתחול. זה אומר שנכריז על מקום לשים ערך, אך לא ניתן לו ערך ראשוני:

var i int

זה יוצר משתנה שהוכרז כ-i מסוג נתונים int.

ניתן לאתחל את הערך באמצעות אופרטור השווה (=), כמו בדוגמה הבאה:

var i int = 1

ב-Go, שתי הצורות של הכרזה זו נקראות הכרזות משתנים ארוכות.

ניתן גם להשתמש ב-הכרזת משתנים קצרה:

i := 1

במקרה זה, יש לנו משתנה בשם i, וסוג נתונים של int. כאשר לא מציינים סוג נתונים, Go יסיק את סוג הנתונים.

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

  • השתמשו רק בצורה ארוכה, var i int, כשאינכם מאתחלים את המשתנה.

  • השתמשו בצורה קצרה, i := 1, בעת הכרזה ואתחול.

  • אם לא רציתם ש-Go יסיק את סוג הנתונים שלכם, אך עדיין רציתם להשתמש בהכרזת משתנים קצרה, תוכלו לעטוף את הערך שלכם בסוג הרצוי, בצורה הבאה:

i := int64(1)

זה לא נחשב לאידיומטי ב-Go להשתמש בצורת ההכרזה על משתנים הארוכה כשאנו מאתחלים את הערך:

var i int = 1

זה טוב לעקוב אחר הדרך שבה הקהילה של Go בדרך כלל מכריזה על משתנים כדי שאחרים יוכלו לקרוא את התוכניות שלכם בלי מנוגד.

ערכים אפס

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

package main

import "fmt"

func main() {
	var a int
	var b string
	var c float64
	var d bool

	fmt.Printf("var a %T = %+v\n", a, a)
	fmt.Printf("var b %T = %q\n", b, b)
	fmt.Printf("var c %T = %+v\n", c, c)
	fmt.Printf("var d %T = %+v\n\n", d, d)
}
Output
var a int = 0 var b string = "" var c float64 = 0 var d bool = false

השתמשנו בפורמט %T בפקודה fmt.Printf. זה אומר לפונקציה להדפיס את סוג הנתונים עבור המשתנה.

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

שמות משתנים: כללים וסגנון

שמות המשתנים די גמישים, אבל יש כמה כללים לזכור:

  • שמות המשתנים חייבים להיות מילה אחת (כלומר ללא רווחים).
  • שמות המשתנים חייבים להיות מורכבים רק מאותיות, מספרים וקווים תחתונים (_).
  • שמות המשתנים לא יכולים להתחיל עם מספר.

לאחר עקיבה אחר כללים אלה, בואו נבחן שמות משתנים תקפים ולא תקפים:

Valid Invalid Why Invalid
userName user-name Hyphens are not permitted
name4 4name Cannot begin with a number
user $user Cannot use symbols
userName user name Cannot be more than one word

בנוסף, זכור כאשר אתה מגדיר שמות משתנים שהם תלויי-אותיות. שמות אלה userName, USERNAME, UserName, ו- uSERnAME הם כולם משתנים שונים לגמרי. זה מומלץ להימנע משימוש בשמות משתנים דומים בתוך התוכנית כדי לוודא שגם אתה וגם שותפיך – גם נוכחיים וגם עתידיים – תוכלו להבין את המשתנים שלכם.

בעוד שמות משתנים הם תלויי-אותיות, האות הראשונה של שם משתנה בעלת משמעות מיוחדת ב-Go. אם משתנה מתחיל באות גדולה, אז המשתנה זמין מחוץ לחבילה שבה הוא הוכרז (או exported). אם משתנה מתחיל באות קטנה, אז הוא זמין רק בתוך החבילה שבה הוא הוכרז.

var Email string
var password string

Email מתחיל באות גדולה וניתן לגשת אליו מחבילות אחרות. password מתחיל באות קטנה, וניתן לגשת אליו רק בתוך החבילה שבה הוא הוכרז.

זה נפוץ ב-Go להשתמש בשמות משתנים קצרים מאוד. בהזדמנות בין להשתמש ב- userName לבין user עבור משתנה, זה יהיה מקובל לבחור ב- user.

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

names := []string{"Mary", "John", "Bob", "Anna"}
for i, n := range names {
	fmt.Printf("index: %d = %q\n", i, n)
}

אנו משתמשים במשתנה names במסגרת גדולה יותר, ולכן זה נורמלי לתת לו שם משמעותי יותר כדי לעזור לזכור מה הוא אומר בתכנית. עם זאת, אנו משתמשים במשתנים i ו-n מייד בשורה הבאה של הקוד, ולאחר מכן לא משתמשים בהם שוב… בגלל זה, זה לא יבלבל מישהו שקורא את הקוד על איפה המשתנים משמשים, או מה הם אומרים.

הבא, בואו נעבור על כמה הערות על סגנון משתנים. הסגנון הוא להשתמש MixedCaps או mixedCaps במקום קווים תחתונים לשמות מרובות מילים.

Conventional Style Unconventional Style Why Unconventional
userName user_name Underscores are not conventional
i index prefer i over index as it is shorter
serveHTTP serveHttp acronyms should be capitalized

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

השמה מחדש של משתנים

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

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

בואו נקצה את הערך של 76 למשתנה בשם i מסוג int, ואז נקצה לו ערך חדש של 42:

package main

import "fmt"

func main() {
	i := 76
	fmt.Println(i)

	i = 42
	fmt.Println(i)
}
Output
76 42

דוגמה זו מראה שאפשר להקצות למשתנה i ערך של מספר שלם תחילה, ואז להקצות מחדש למשתנה i ערך של 42.

הערה: כשמכריזים ומאתחלים משתנה, אפשר להשתמש ב-:=, אבל כשרוצים לשנות פשוט את הערך של משתנה שכבר הוכרז, מספיק להשתמש באופרטור השווה (=).

מכיוון ש-Go היא שפה מסוגתית (typed), אין באפשרותנו להקצות סוג אחד לאחר. למשל, אין באפשרותנו להקצות את הערך "Sammy" למשתנה מסוג int:

i := 72
i = "Sammy"

ניסיון להקצות סוגים שונים זה לזה יגרום לשגיאת קומפילציה:

Output
cannot use "Sammy" (type string) as type int in assignment

Go לא תאפשר לנו להשתמש בשם משתנה יותר מפעם אחת:

var s string
var s string
Output
s redeclared in this block

אם ננסה להשתמש בהצהרה קצרה של משתנה יותר מפעם אחת עבור אותו שם משתנה, נקבל גם שגיאת קומפילציה. זה יכול לקרות בטעות, ולכן הבנה מה משמעות הודעת השגיאה עוזרת:

i := 5
i := 10
Output
no new variables on left side of :=

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

הקצאה מרובה

גם ב-Go מאפשרים לנו להקצות מספר ערכים למספר משתנים באותה שורה. כל אחד מהערכים הללו יכול להיות מסוג נתונים שונה:

j, k, l := "shark", 2.05, 15
fmt.Println(j)
fmt.Println(k)
fmt.Println(l)
Output
shark 2.05 15

בדוגמה זו, המשתנה j הוקצה למחרוזת "shark", המשתנה k הוקצה למספר עשרוני 2.05, והמשתנה l הוקצה למספר שלם 15.

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

משתנים גלובליים ומשתנים מקומיים

בשימוש במשתנים בתוך תוכנית, חשוב לשמור על היקף המשתנה במוחם. היקף המשתנה מתייחס למקומות מסוימים שבהם הוא נגיש מתוך הקוד של תוכנית נתונה. זה אומר שלא כל המשתנים נגישים מכל חלקים של תוכנית נתונה – חלקם יהיו גלובליים וחלקם יהיו מקומיים.

משתנים גלובליים קיימים מחוץ לפונקציות. משתנים מקומיים קיימים בתוך פונקציות.

בואו נבחן משתנים גלובליים ומקומיים בפעולה:

package main

import "fmt"


var g = "global"

func printLocal() {
	l := "local"
	fmt.Println(l)
}

func main() {
	printLocal()
	fmt.Println(g)
}
Output
local global

כאן אנו משתמשים ב-var g = "global" כדי ליצור משתנה גלובלי מחוץ לפונקציה. לאחר מכן אנו מגדירים את הפונקציה printLocal(). בתוך הפונקציה מוקצה משתנה מקומי בשם l ולאחר מכן מודפס. התכנית מסתיימת על ידי קריאה ל-printLocal() ולאחר מכן הדפסת המשתנה הגלובלי g.

מכיוון ש-g הוא משתנה גלובלי, ניתן להתייחס אליו ב-printLocal(). בואו נשנה את התכנית הקודמת כדי לעשות זאת:

package main

import "fmt"


var g = "global"

func printLocal() {
	l := "local"
	fmt.Println(l)
	fmt.Println(g)
}

func main() {
	printLocal()
	fmt.Println(g)
}
Output
local global global

אנו מתחילים על ידי הכרזה על משתנה גלובלי g, var g = "global". בפונקציה main, אנו קוראים לפונקציה printLocal, שמגדירה משתנה מקומי l ומדפיסה אותו, fmt.Println(l). לאחר מכן, printLocal מדפיסה את המשתנה הגלובלי g, fmt.Println(g). למרות ש-g לא הוגדר בתוך printLocal, עדיין יכול היה לגשת אליו מכיוון שהוא היה מוכרז במרחב גלובלי. לבסוף, הפונקציה main גם מדפיסה את g.

עכשיו בואו ננסה לקרוא למשתנה המקומי מחוץ לפונקציה:

package main

import "fmt"

var g = "global"

func printLocal() {
	l := "local"
	fmt.Println(l)
}

func main() {
	fmt.Println(l)
}

Output
undefined: l

אין באפשרותנו להשתמש במשתנה מקומי מחוץ לפונקציה שבה הוא מוקצה. אם תנסה לעשות זאת, תקבל שגיאת undefined בעת הקמפילה.

בואו נביט בדוגמה נוספת שבה אנו משתמשים באותו שם משתנה עבור משתנה גלובלי ומשתנה מקומי:

package main

import "fmt"

var num1 = 5

func printNumbers() {
	num1 := 10
	num2 := 7  

	fmt.Println(num1)
	fmt.Println(num2)
}

func main() {
	printNumbers()
	fmt.Println(num1)
}
Output
10 7 5

בתכנית זו, הכרזנו על המשתנה num1 פעמיים. ראשית, הכרזנו על num1 בטווח הגלובלי, var num1 = 5, ושוב בטווח המקומי של הפונקציה printNumbers, num1 := 10. כאשר אנו מדפיסים את num1 מתוך התכנית main, אנו רואים את הערך 5 מודפס. זה בגלל ש-main רואה רק את ההכרזה על המשתנה הגלובלי. עם זאת, כאשר אנו מדפיסים את num1 מתוך הפונקציה printNumbers, היא רואה את ההכרזה המקומית, ותדפיס את הערך 10. למרות ש-printNumbers יוצרת משתנה חדש בשם num1 ומקצה לו ערך של 10, זה לא משפיע על המופע הגלובלי של num1 עם הערך 5.

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

קבועים

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

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

כדי להגדיר קבוע, נוכל להשתמש בתחביר הבא:

const shark = "Sammy"
fmt.Println(shark)
Output
Sammy

אם ננסה לשנות קבוע לאחר שהוא הוכרז, נקבל שגיאת קומפילציה:

Output
cannot assign to shark

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

package main

import "fmt"

const (
	year     = 365
	leapYear = int32(366)
)

func main() {
	hours := 24
	minutes := int32(60)
	fmt.Println(hours * year)    
	fmt.Println(minutes * year)   
	fmt.Println(minutes * leapYear)
}
Output
8760 21900 21960

אם תגדיר קבוע עם סוג, הוא יהיה בדיוק מהסוג הזה. כאן כשאנו מגדירים את הקבוע leapYear, אנו מגדירים אותו כסוג נתונים int32. לכן זהו קבוע מוגדר, כלומר הוא יכול לפעול רק עם סוגי נתונים int32. הקבוע year שאנו מגדירים ללא סוג, ולכן הוא נחשב לא מוגדר. בגלל זה, אפשר להשתמש בו עם כל סוג נתונים שלם.

כשהוגדר hours, הוא הסק שהוא מסוג int כי לא נתנו לו סוג מפורש, hours := 24. כשהגדרנו את minutes, הכרזנו עליו כint32, minutes := int32(60).

עכשיו בואו נעבור על כל חישוב ולמה הוא עובד:

hours * year

במקרה זה, שעות הוא int, ו-שנים הוא ללא טיפוס. כאשר התוכנית מתקמפלת, היא ממירה במפורש שנים ל-int, מה שמאפשר לפעולת הכפל להצליח.

minutes * year

במקרה זה, דקות הוא int32, ו-שנה הוא ללא טיפוס. כאשר התוכנית מתקמפלת, היא ממירה במפורש שנים ל-int32, מה שמאפשר לפעולת הכפל להצליח.

minutes * leapYear

במקרה זה, דקות הוא int32, ו-שנת מעופף הוא קבוע מטיפוס של int32. אין מה שהקומפיילר צריך לעשות הפעם מאחר ושתי המשתנים כבר מאותו הטיפוס.

אם ננסה להכפיל שני טיפוסים שהם מטיפוס ולא תואמים, התוכנית לא תתקמפל:

fmt.Println(hours * leapYear)
Output
invalid operation: hours * leapYear (mismatched types int and int32)

במקרה זה, שעות הושג כ-int, ו-שנת מעופף הוכרז במפורש כ-int32. מאחר ש-Go היא שפה מטיפוסית, int ו-int32 אינם תואמים לפעולות מתמטיות. כדי להכפיל אותם, תצטרך להמיר אחד ל-int32 או ל-int.

מסקנה

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

Source:
https://www.digitalocean.com/community/tutorials/how-to-use-variables-and-constants-in-go