نوع rune در Go معادلی برای int32 است. با این نوع زیرین int32، نوع rune یک مقدار عدد صحیح علامتدار ۳۲ بیتی را نگه میدارد. اما برخلاف نوع int32، مقدار عدد صحیحی که در نوع rune ذخیره میشود، یک کاراکتر یونیکد را نمایش میدهد.
یونیکد ابرمجموعهای از ASCII است که کاراکترها را با تخصیص یک عدد یکتا به هر کاراکتر نمایش میدهد. به این عدد یکتا، «نقطهی کد یونیکد» میگویند. یونیکد در پی آن است که همهی کاراکترهای جهان، از جمله الفباهای گوناگون، اعداد، نمادها و حتی ایموجی را بهصورت نقطههای کد یونیکد نمایش دهد.
در Go، نوع rune نشاندهندهی یک نقطهی کد یونیکد است.
جدول زیر نمونههایی از کاراکترهای یونیکد را همراه با نقطهی کد و مقدار اعشاریشان نشان میدهد:
| کاراکتر یونیکد | نقطهی کد یونیکد | مقدار اعشاری |
|---|---|---|
| 0 | U+0030 |
48 |
| A | U+0041 |
65 |
| a | U+0061 |
97 |
| ¿ | U+00BF |
191 |
| π | U+03C0 |
960 |
| 🧠 | U+1F9E0 |
129504 |
UTF-8 یک کدگذاری کاراکتر با عرض متغیر است که برای کدگذاری هر نقطهی کد یونیکد در قالب ۱، ۲، ۳ یا ۴ بایت استفاده میشود. چون یک نقطهی کد یونیکد حداکثر میتواند در ۴ بایت کدگذاری شود، نوع rune باید بتواند دادهای تا ۴ بایت را نگه دارد. به همین دلیل نوع rune معادلی برای int32 است، چون نوع int32 توان نگهداشتن دادهای تا ۴ بایت را دارد.
فایلهای کد منبع Go با UTF-8 کدگذاری میشوند.
runeهامتغیرهایی از نوع rune با قرار دادن یک کاراکتر داخل کوتیشن تک اعلام میشوند:
myRune := '¿'
چون rune فقط معادلی برای int32 است، چاپ نوع یک rune مقدار int32 را به دست میدهد:
myRune := '¿'
fmt.Printf("myRune type: %T\n", myRune)
// Output: myRune type: int32
به همین ترتیب، چاپ مقدار یک rune مقدار عدد صحیح (اعشاری) آن را به دست میدهد:
myRune := '¿'
fmt.Printf("myRune value: %v\n", myRune)
// Output: myRune value: 191
برای چاپ کاراکتر یونیکدی که با rune نشان داده میشود، از نشانگر قالببندی %c استفاده کنید:
myRune := '¿'
fmt.Printf("myRune Unicode character: %c\n", myRune)
// Output: myRune Unicode character: ¿
برای چاپ نقطهی کد یونیکدی که با rune نشان داده میشود، از نشانگر قالببندی %U استفاده کنید:
myRune := '¿'
fmt.Printf("myRune Unicode code point: %U\n", myRune)
// Output: myRune Unicode code point: U+00BF
علاوه بر اینکه میتوانید یک rune را با قرار دادن کاراکتر داخل کوتیشن تک تعریف کنید، میتوانید عدد را بهصورت هگزادسیمال یا اعشاری هم بنویسید:
myRune := rune(0xbf)
myRune = 191
fmt.Printf("myRune Unicode character: %c\n", myRune)
// Output: myRune Unicode character: ¿
runeها و رشتههارشتهها در Go با UTF-8 کدگذاری میشوند، یعنی شامل کاراکترهای یونیکد هستند. کاراکترهای داخل رشتهها بسته به کاراکتر یونیکدی که نمایش میدهند، در ۱، ۲، ۳ یا ۴ بایت ذخیره و کدگذاری میشوند.
در Go، از اسلایسها برای نمایش دنبالهها استفاده میشود و میتوان روی این اسلایسها با range پیمایش کرد. وقتی روی یک رشته پیمایش میکنیم، Go رشته را به مجموعهای از runeها تبدیل میکند که هر کدام ۴ بایت است (یادتان باشد، نوع rune معادلی برای int32 است!)
حتی با اینکه یک رشته فقط اسلایسی از بایتهاست، کلیدواژهی range روی runeهای یک رشته پیمایش میکند، نه روی بایتهای آن.
در این مثال، متغیر index نشاندهندهی اندیس شروع دنبالهی بایتی rune جاری است و متغیر char نشاندهندهی rune جاری است:
myString := "❗hello"
for index, char := range myString {
fmt.Printf("Index: %d\tCharacter: %c\t\tCode Point: %U\n", index, char, char)
}
// Output:
// Index: 0 Character: ❗ Code Point: U+2757
// Index: 3 Character: h Code Point: U+0068
// Index: 4 Character: e Code Point: U+0065
// Index: 5 Character: l Code Point: U+006C
// Index: 6 Character: l Code Point: U+006C
// Index: 7 Character: o Code Point: U+006F
چون runeها میتوانند در ۱، ۲، ۳ یا ۴ بایت ذخیره شوند، طول یک رشته همیشه با تعداد کاراکترهای آن رشته برابر نیست. از تابع توکار len برای گرفتن طول یک رشته بر حسب بایت و از تابع utf8.RuneCountInString برای گرفتن تعداد runeهای یک رشته استفاده کنید:
import "unicode/utf8"
myString := "❗hello"
stringLength := len(myString)
numberOfRunes := utf8.RuneCountInString(myString)
fmt.Printf("myString - Length: %d - Runes: %d\n", stringLength, numberOfRunes)
// Output: myString - Length: 8 - Runes: 6
runeهایک اسلایس از runeها را میتوان به رشته تبدیل نوع کرد:
myRuneSlice := []rune{'e', 'x', 'e', 'r', 'c', 'i', 's', 'm'}
myString := string(myRuneSlice)
fmt.Println(myString)
// Output: exercism
به همین ترتیب، یک رشته را میتوان به اسلایسی از runeها تبدیل نوع کرد. یادتان باشد، بدون نشانگرهای قالببندی، چاپ یک rune مقدار عدد صحیح (اعشاری) آن را به دست میدهد:
myString := "exercism"
myRuneSlice := []rune(myString)
fmt.Println(myRuneSlice)
// Output: [101 120 101 114 99 105 115 109]