رو

رون در Go

3 تمرین

درباره‌ی رون

نوع 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

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]
ویرایش از طریق GitHub این پیوند در پنجره یا زبانه‌ی جدیدی باز می‌شود

رون را یاد بگیرید

تمرین کردن قفل شده است

برای تمرین رون قفل 2 تمرین دیگر را باز کنید