مسیرها
/
Go
Go
/
تمرین‌ها
/
اتاق مرتب‌سازی
اتاق مرتب‌سازی

اتاق مرتب‌سازی

تمرین یادگیری

مقدمه

تبدیل نوع

در Go، تبدیل بین نوع‌های مختلف باید صریح باشد. تبدیل بین نوع‌ها (که به آن تبدیل نوع هم می‌گویند) از طریق تابعی انجام می‌شود که اسم نوع مقصد را دارد. برای نمونه، برای تبدیل یک int به float64 باید به این شکل عمل کنید:

var x int = 42 // x has type int
f := float64(x) // f has type float64 (ie. 42.0)

تبدیل بین نوع‌های پایه و رشته‌ها

بسته‌ای به نام strconv برای تبدیل بین نوع‌های پایه (مثل int) و string وجود دارد.

import "strconv"

var intString string = "42"
var i, err = strconv.Atoi(intString)

var number int = 12
var s string = strconv.Itoa(number)

تأیید نوع

رابط‌ها در Go می‌توانند درباره‌ی نوع زیرین ابهام ایجاد کنند. تأیید نوع به ما اجازه می‌دهد تا مقدار مشخص زیرینِ مقدار رابط را با این نحوه‌ی نگارش بیرون بکشیم: interfaceVariable.(concreteType).

برای نمونه:

var input any = 12
number := input.(int)

توجه: اگر متغیر رابط مقداری از نوع مشخص را نگه ندارد، این کار باعث panic می‌شود.

می‌توانیم با استفاده از هر دو مقدار بازگشتی تأیید نوع بررسی کنیم که آیا مقدار رابط یک نوع مشخص خاص را نگه می‌دارد یا نه: مقدار زیرین و یک «مقدار منطقی» که گزارش می‌دهد آیا تأیید موفق بوده است یا نه. برای نمونه:

str, ok := input.(string) // no panic if input is not a string

اگر input یک string نگه دارد، str مقدار زیرین خواهد بود و ok برابر با «درست» خواهد بود. اگر input یک string نگه ندارد، str مقدار صفر نوع string خواهد بود (یعنی ""، رشته‌ی خالی) و ok برابر با «غلط» خواهد بود. در هیچ حالتی panic رخ نمی‌دهد.

سوئیچ نوع

یک سوئیچ نوع می‌تواند چندین تأیید نوع را پشت سر هم انجام دهد. نحوه‌ی نگارش آن همانند تأیید نوع است (interfaceVariable.(concreteType))، اما concreteType با کلیدواژه‌ی type جایگزین می‌شود. برای نمونه:

var i any = 12 // try: 12.3, true, int64(12), []int{}, map[string]int{}

switch v := i.(type) {
case int:
    fmt.Printf("the integer %d\n", v)
case string:
    fmt.Printf("the string %s\n", v)
default:
    fmt.Printf("type, %T, not handled explicitly: %#v\n", v, v)
}

دستورالعمل‌ها

جِن در اتاق مرتب‌سازی یک کارخانه‌ی بزرگ کار می‌کند. اتاق مرتب‌سازی باید هر چه را که واردش می‌شود پردازش کند و آن را با یک برچسب دسته‌بندی کند. جِن مسئول مواردی است که از پیش به عنوان عدد دسته‌بندی شده‌اند. او به برنامه‌ای نیاز دارد که در مرتب‌سازی کمکش کند.

بیشتر مقادیر اولیه باید برچسب‌های سرراستی بگیرند. برای اعداد، او رشته‌هایی می‌خواهد که بگویند "This is the number 2.0" (اگر عدد ۲ بود). جِن برای اعداد صحیح و اعداد اعشاری همین خروجی را می‌خواهد.

چند رابط Box وجود دارد که باید بازگشایی شوند تا محتوایشان به دست بیاید. برای یک NumberBox، او رشته‌هایی می‌خواهد که بگویند "This is a box containing the number 3.0" (اگر متد Number() مقدار ۳ را برگرداند). برای یک FancyNumberBox، او رشته‌هایی می‌خواهد که بگویند "This is a fancy box containing the number 4.0"، اما فقط اگر نوع آن FancyNumber باشد.

هر مورد غیرمنتظره‌ای باید بگوید "Return to sender" تا جِن بتواند آن‌ها را به همان جایی که از آن آمده‌اند پس بفرستد.

1. توصیف اعداد ساده

جِن می‌خواهد اعداد رشته‌هایی مانند "This is the number 2.0" برگردانند (با یک رقم پس از ممیز):

fmt.Println(DescribeNumber(-12.345))
// Output: This is the number -12.3

2. توصیف یک جعبه‌ی عدد

جِن می‌خواهد جعبه‌های عدد رشته‌هایی مانند "This is a box containing the number 2.0" برگردانند (باز هم با یک رقم پس از ممیز):

fmt.Println(DescribeNumberBox(numberBoxContaining{12}))
// Output: This is a box containing the number 12.0

3. پیاده‌سازی متدی که عدد را از یک جعبه‌ی عدد تجملی بیرون می‌کشد

جِن به یک تابع کمکی نیاز دارد که عدد را از یک FancyNumberBox بیرون بکشد. اگر FancyNumberBox از نوع FancyNumber باشد، مقدارش را استخراج کنید و آن را از string به int تبدیل کنید. هر نوع دیگری از FancyNumberBox باید ۰ را برگرداند.

fmt.Println(ExtractFancyNumber(FancyNumber{"10"}))
// Output: 10
fmt.Println(ExtractFancyNumber(AnotherFancyNumber{"4"}))
// Output: 0

4. توصیف یک جعبه‌ی عدد تجملی

اگر FancyNumberBox از نوع FancyNumber باشد، جِن رشته‌هایی می‌خواهد که بگویند "This is a fancy box containing the number 4.0". هر نوع دیگری از FancyNumberBox باید بگوید "This is a fancy box containing the number 0.0".

fmt.Println(DescribeFancyNumberBox(FancyNumber{"10"}))
// Output: This is a fancy box containing the number 10.0
fmt.Println(DescribeFancyNumberBox(AnotherFancyNumber{"4"}))
// Output: This is a fancy box containing the number 0.0

توجه: باید از تابع ExtractFancyNumber استفاده کنیم!

5. پیاده‌سازی DescribeAnything که از همه‌ی آن‌ها استفاده می‌کند

این همان تابع اصلی است که جِن نیاز دارد و هر ورودی‌ای را می‌پذیرد. DescribeAnything باید بر اساس نوع مقداری که به آن داده می‌شود، کار را به توابع دیگر واگذار کند. به طور مشخص:

  • int و float64 هر دو باید به DescribeNumber واگذار کنند
  • NumberBox باید به DescribeNumberBox واگذار کند
  • FancyNumberBox باید به DescribeFancyNumberBox واگذار کند
  • در غیر این صورت باید "Return to sender" برگردانده شود
fmt.Println(DescribeAnything(numberBoxContaining{12.345}))
// Output: This is a box containing the number 12.3
fmt.Println(DescribeAnything("some string"))
// Output: Return to sender
ویرایش از طریق GitHub این لینک در پنجره یا زبانه‌ی جدیدی باز می‌شود
Go Exercism

آماده‌اید اتاق مرتب‌سازی را شروع کنید؟

در Exercism ثبت‌نام کنید تا Go را همراه با 34 مفهوم166 تمرین و مربی‌گری انسانی واقعی یاد بگیرید و در آن استاد شوید، همه‌ی این‌ها رایگان.