Menu

Golang int to string, string to int והמרת טיפוסים

איך ממירים בין טיפוסים ב-Go: int למחרוזת ומחרוזת ל-int עם strconv, מספרים עשרוניים למספרים שלמים, המרות מספריות עם T(v), bytes ו-runes, המלכודת של string(65), וטיפול בשגיאות המרה.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

Go אף פעם לא ממירה טיפוסים באופן מרומז. ממירים בין טיפוסים תואמים עם T(v), ובין מספרים לטקסט עם החבילה strconv. שתי ההמרות שהכי מחפשים:

strconv.Itoa ("integer to ASCII") מעצבת int כטקסט עשרוני. strconv.Atoi ("ASCII to integer") מפענחת טקסט ל-int ומחזירה שגיאה כשהטקסט הוא לא מספר תקין. תמיד בדקו את השגיאה הזאת.

ההמרה T(v)

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

  1. בין טיפוסים מספריים (int, int64, float64, uint8, ...),
  2. בין string לבין []byte או []rune,
  3. בין טיפוסים שחולקים טיפוס בסיס (Celsius ו-float64).

קראו את התוצאות בעיון:

  • int(3.9) הוא 3 ו-int(-3.9) הוא -3. המרה מקצצת לכיוון אפס; היא לא מעגלת. השתמשו קודם ב-math.Round, math.Floor או math.Ceil כדי לבחור את ההתנהגות. math.Round מעגלת חצאים הרחק מאפס, כך ש--3.5 הופך ל--4.
  • uint8(300) הוא 44, כי רק 8 הביטים הנמוכים שורדים (300 פחות 256), ו-int8(200) הוא -56 מאותה סיבה. אין שגיאה, אין panic.
  • Celsius ו-float64 חולקים טיפוס בסיס, ולכן הם מומרים בחופשיות, אבל רק במפורש.

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

קבועים נבדקים, משתנים לא

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

fmt.Println(uint8(300)) // compile error
x := 300
fmt.Println(uint8(x)) // 44
./main.go:6:20: constant 300 overflows uint8

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

./main.go:7:18: cannot convert -3.9 (untyped float constant) to type int

אם הערך העשרוני מחוץ לטווח של טיפוס היעד השלם (למשל int64(1e20)), התוצאה תלויה במימוש: amd64 ו-arm64, לדוגמה, נותנות תשובות שונות. בדקו את הטווח לפני המרה של ערכים לא מהימנים.

המרת מספרים למחרוזות

מפונקציהדוגמהתוצאה
intstrconv.Itoa(n)strconv.Itoa(-7)"-7"
int64strconv.FormatInt(n, base)strconv.FormatInt(255, 16)"ff"
uint64strconv.FormatUint(n, base)strconv.FormatUint(5, 2)"101"
float64strconv.FormatFloat(f, fmt, prec, 64)strconv.FormatFloat(3.14159, 'f', 2, 64)"3.14"
boolstrconv.FormatBool(b)strconv.FormatBool(true)"true"
כל דברfmt.Sprint(v)fmt.Sprint(3.5)"3.5"
כל דבר, מעוצבfmt.Sprintf(format, v)fmt.Sprintf("%05d", 42)"00042"

FormatFloat מקבלת בית של פורמט ('f' לנקודה קבועה, 'e' למעריך, 'g' למה שקצר יותר), דיוק (-1 פירושו "הכי מעט ספרות שמאפשרות שחזור מדויק"), וגודל הביטים של ה-float המקורי (64 או 32).

strconv מהירה יותר מ-fmt.Sprint, שעוטפת את הערך ב-interface ועוברת במסלול העיצוב הכללי של fmt. בלולאה חמה ההבדל הזה מורגש; להמרות מזדמנות, בחרו במה שנקרא טוב יותר.

המרת מחרוזות למספרים

אלפונקציהמחזירה
intstrconv.Atoi(s)int, error
כל int עם סימןstrconv.ParseInt(s, base, bitSize)int64, error
כל int בלי סימןstrconv.ParseUint(s, base, bitSize)uint64, error
floatstrconv.ParseFloat(s, bitSize)float64, error
boolstrconv.ParseBool(s)bool, error

ParseInt תמיד מחזירה int64. הארגומנט bitSize (0, 8, 16, 32, 64) קובע את הטווח שהיא מקבלת, כך שמובטח שהתוצאה תיכנס כשממירים אותה לטיפוס קטן יותר. base 0 פירושו "הסק מהתחילית", כך ש-0x1f, 0o17, 0b101 ו-1_000 כולם מתפענחים.

מה שהפלט מראה:

  • " 42" נכשל. Atoi מקבלת סימן אופציונלי וספרות, ושום דבר אחר. קלט מ-bufio בדרך כלל נגמר ב-\n, אז הסירו אותו.
  • "4.2" לא תקין עבור Atoi. השתמשו ב-ParseFloat למספרים עשרוניים.
  • בשגיאת חריגה מהטווח, ParseInt מחזירה את הערך הגדול ביותר שנכנס (127 עבור int8) יחד עם השגיאה. אל תשתמשו בערך כשהשגיאה היא לא nil.
  • השגיאות הן ערכי *strconv.NumError שעוטפים את strconv.ErrSyntax או את strconv.ErrRange, כך ש-errors.Is יכולה להבחין ביניהן.

ParseBool מקבלת 1, t, T, TRUE, true, True ואת צורות ה-false המקבילות. "yes" ו-"on" הן שגיאות.

המלכודת של string(65)

המרה של מספר שלם ל-string לא מייצרת ספרות. היא מייצרת את התו עם ה-code point הזה של Unicode:

n := 65
s := string(n) // "A", not "65"

המהדר מקבל את זה, אבל go vet מדווח על זה:

./main.go:10:7: conversion from int to string yields a string of one rune, not a string of digits

אם באמת רוצים את התו, אמרו את זה עם rune: string(rune(n)). אם רוצים את המספר כטקסט, השתמשו ב-strconv.Itoa(n). המרה של rune או byte ל-string תקינה ונפוצה:

מחרוזות, bytes ו-runes

string, []byte ו-[]rune מומרים זה לזה עם T(v). כל המרה מעתיקה את הנתונים, כי מחרוזות הן immutable ו-slices לא:

המירו ל-[]rune כשצריך לגשת לפי אינדקס או לשנות לפי תו; המירו ל-[]byte לקלט ופלט, ל-hashing ולעריכות ברמת הבית. הדף על runes ו-bytes מכסה UTF-8 בפירוט.

המרה מול type assertion

המרה משנה ערך מטיפוס קונקרטי אחד לאחר. הוצאת הערך הקונקרטי מתוך interface (any, error, io.Reader) היא פעולה אחרת, ה-type assertion:

var v any = 42

n := v.(int)       // type assertion: v holds an int, give it to me
f := float64(n)    // conversion: int to float64
// f := float64(v) // compile error: cannot convert v (variable of interface type any)
//                  // to type float64: need type assertion

קודם assertion, אחר כך המרה. צורת ה-comma-ok n, ok := v.(int) מונעת panic כשהטיפוס שגוי.

תקציר מהיר

משימהקוד
int למחרוזתstrconv.Itoa(n)
int64 למחרוזתstrconv.FormatInt(n, 10)
מחרוזת ל-intn, err := strconv.Atoi(s)
מחרוזת ל-int64n, err := strconv.ParseInt(s, 10, 64)
מחרוזת ל-float64f, err := strconv.ParseFloat(s, 64)
float64 למחרוזתstrconv.FormatFloat(f, 'f', -1, 64)
float64 ל-intint(f) (מקצץ) או int(math.Round(f))
int ל-float64float64(n)
מחרוזת ל-[]byte[]byte(s)
[]byte למחרוזתstring(b)
rune למחרוזתstring(r)
bool למחרוזתstrconv.FormatBool(b)
כל ערך למחרוזתfmt.Sprint(v)

שאלות נפוצות

איך ממירים int למחרוזת ב-Go?

השתמשו ב-strconv.Itoa(n): strconv.Itoa(42) מחזירה "42". ל-int64 השתמשו ב-strconv.FormatInt(n, 10). גם fmt.Sprint(n) עובדת לכל טיפוס אבל היא איטית יותר. אל תכתבו string(n): זה מתייחס ל-n כאל code point של Unicode, ולכן string(65) הוא "A".

איך ממירים מחרוזת ל-int ב-Go?

השתמשו ב-strconv.Atoi, שמחזירה את המספר ושגיאה:

n, err := strconv.Atoi("42")
if err != nil {
	// not a valid integer
}

לגודל או לבסיס מסוים, השתמשו ב-strconv.ParseInt(s, 10, 64), שמחזירה int64. Atoi לא מסירה רווחים, ולכן " 42" היא שגיאה; קראו קודם ל-strings.TrimSpace.

איך עושים cast ב-Go?

ב-Go זה נקרא המרה, והתחביר הוא T(v): float64(n), int(f), []byte(s). זה עובד בין טיפוסים מספריים, בין מחרוזות ל-slices של bytes או runes, ובין טיפוסים עם אותו טיפוס בסיס. זה לא מפענח טקסט: הפיכת "42" ל-42 דורשת strconv. הוצאת טיפוס קונקרטי מתוך interface היא type assertion, v.(T), לא המרה.

איך ממירים float ל-int ב-Go?

int(f) מקצץ לכיוון אפס: int(3.9) הוא 3 ו-int(-3.9) הוא -3. כדי לעגל, השתמשו ב-int(math.Round(f)). אם ה-float מחוץ לטווח של טיפוס המספר השלם, התוצאה תלויה במימוש, אז בדקו את הטווח קודם כשהערך מגיע מקלט.

למה string(65) מחזיר "A" ב-Go?

המרה של מספר שלם ל-string מפרשת אותו כ-code point של Unicode, ו-65 הוא ה-code point של A. go vet מסמן את זה: conversion from int to string yields a string of one rune, not a string of digits. השתמשו ב-strconv.Itoa(65) כדי לקבל "65".

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל