کریستال چیزی دارد که به آن «عبارتهای کنترلی» میگویند. اینها برای کنترل نحوهی اجرای برنامه به کار میروند و یک مقدار درست یا غلط میگیرند. عملگرهایی وجود دارند که میتوان با آنها مقدارهای درست یا غلط ساخت؛ به اینها عملگرهای برابری و مقایسه میگویند.
دو عبارت کنترلی اصلی وجود دارد که تعیین میکنند کدام بخش از کد اجرا شود و کدام اجرا نشود. به بیان دیگر، مشخص میکنند کدام «شاخه» اجرا خواهد شد.
این دو عبارتاند: if و عبارت unless.
از عملگرهای مقایسه برای مقایسهی مقدارها استفاده میشود و یک مقدار true یا false برمیگردانند.
این عملگرها نیاز دارند که دو مقدار از یک نوع با هم مقایسه شوند.
اگر مقدارها همنوع نباشند، کامپایلر خطا میدهد.
در ادامه فهرستی از عملگرهای مقایسه و مثالی از زمانی که مقدار true میدهند میآید:
| متد | توضیح | مثال |
|---|---|---|
| < | کوچکتر از | 4 < 5 |
| <= | کوچکتر یا مساوی | 4 <= 4 |
| > | بزرگتر از | 3 > 1 |
| >= | بزرگتر یا مساوی | 2 >= 2 |
عملگرهای برابری شبیه عملگرهای مقایسهاند، اما برای بررسی برابری یا نابرابری دو مقدار به کار میروند.
عملگر == بررسی میکند که آیا دو مقدار برابرند، از جمله نوع مقدار.
اگر مقدارها یکسان باشند true و در غیر این صورت false برمیگرداند.
عملگر == میتواند هر نوع مقداری را با هر نوع مقدار دیگری مقایسه کند.
عملگر != هم به همین شکل کار میکند، اما اگر مقدارها برابر نباشند true و اگر برابر باشند false برمیگرداند.
if
از دستور if برای بررسی درست یا غلط بودن یک شرط دادهشده استفاده میشود.
اگر شرط درست باشد، کد داخل دستور if اجرا میشود.
یک دستور if با کلیدواژهی end به پایان میرسد.
if 1 == 1
puts "1 is equal to 1"
end
# => 1 is equal to 1
if 1 > 2
puts "1 is greater than 2"
end
# => no output
unless
دستور unless بسیار شبیه دستور if کار میکند، اما اگر شرط غلط باشد، کد داخل دستور unless را اجرا میکند.
unless 1 == 1
puts "1 is not equal to 1"
end
# => no output
unless 1 > 2
puts "1 is not greater than 2"
end
# => 1 is not greater than 2
else
از دستور else میتوان همراه با دستورهای if و unless استفاده کرد.
دستور else زمانی اجرا میشود که شاخهی if یا شاخهی unless اجرا نشده باشد.
هرچند میتوان از شاخهی `else` همراه با `unless,` استفاده کرد، اما این کار توصیه نمیشود چون خوانایی را کاهش میدهد.
در عوض، استفاده از `if !condition` همراه با یک شاخهی else توصیه میشود.
if 1 == 1
puts "1 is equal to 1"
else
puts "1 is not equal to 1"
end
# => 1 is equal to 1
unless 1 < 2
puts "1 is not greater than 2"
else
puts "1 is greater than 2"
end
# => 1 is greater than 2
if
از دستور elsif میتوان همراه با دستور if استفاده کرد.
دستور elsif زمانی اجرا میشود که شاخهی if اجرا نشده باشد و شرط دستور elsif درست باشد.
دستورهای elsif را میتوان پشت سر هم زنجیره کرد و اولین شرط درست اجرا میشود.
همچنین میتواند یک دستور else در پایان دستور if باشد که اگر هیچیک از دستورهای پیشین درست نبوده باشد، اجرا میشود.
if 1 != 1
puts "1 is not equal to 1"
elsif 1 > 2
puts "1 is greater than 2"
else
puts "1 is not equal to 1 and 1 is not greater than 2"
end
# => 1 is not equal to 1 and 1 is not greater than 2
وقتی در شاخههای مختلف مقادیری از نوعهای متفاوت به متغیر نسبت داده شود، متغیر هر دو نوع را در خود نگه میدارد. این به آن دلیل است که کامپایلر نمیداند کدام شاخه اجرا خواهد شد. این مقداردهی چندگانه که به آن «اتحاد» هم میگویند، در مفاهیم بعدی توضیح داده میشود. این موضوع در مثال زیر دیده میشود:
if 1 == 1
a = 1
else
a = "1"
end
typeof(a) # => Int32 | String
کریستال یک عملگر سهتایی دارد، یک دستور if-else تکخطی: condition ? expression_if_truthy : expression_if_falsey
1 == 1 ? puts("1 is equal to 1") : puts("1 is not equal to 1")
# => 1 is equal to 1
در این تمرین، یک سیستم کنترل ساده برای یک راکتور هستهای توسعه میدهیم.
راکتور برای تولید توان باید در حالت بحرانی باشد. اگر راکتور در وضعیتی کمتر از حالت بحرانی باشد، ممکن است آسیب ببیند. اگر وضعیت راکتور از حالت بحرانی فراتر برود، ممکن است دچار اضافهبار شود و به ذوب هسته بیانجامد. میخواهیم احتمال ذوب هسته را کاهش دهیم و وضعیت راکتور را بهدرستی مدیریت کنیم.
سه تمرین زیر همگی به نوشتن کدی مربوط میشوند که وضعیت ایدهآل راکتور را حفظ کند.
نخستین کاری که یک سیستم کنترل باید انجام دهد، بررسی این است که آیا راکتور در حالت بحرانی متعادل است یا نه. راکتور زمانی بحرانی در نظر گرفته میشود که شرایط زیر را برآورده کند:
متد Reactor.criticality_balanced? را پیادهسازی کنید که temperature برحسب کلوین و neutrons_emitted را بهعنوان پارامتر میگیرد و اگر شرایط بحرانی برآورده شده باشد true و در غیر این صورت false برمیگرداند.
Reactor.criticality_balanced?(750, 600)
# => true
وقتی راکتور شروع به تولید توان کرد، باید بازدهی آن مشخص شود. بازدهی را میتوان در ۴ محدوده دستهبندی کرد:
green -> بازدهی ۸۰٪ یا بیشتر،orange -> بازدهی کمتر از ۸۰٪ اما حداقل ۶۰٪،red -> بازدهی کمتر از ۶۰٪، اما همچنان ۳۰٪ یا بیشتر،black -> بازدهی کمتر از ۳۰٪.مقدار درصد را میتوان بهصورت (generated_power/theoretical_max_power)*100 محاسبه کرد، که در آن generated_power = voltage * current است.
توجه کنید که مقدار درصد معمولاً یک عدد صحیح نیست، بنابراین دقت کنید که از مقایسههای < و <= بهدرستی استفاده کنید.
متد Reactor.reactor_efficiency را با سه پارامتر پیادهسازی کنید: voltage، current و theoretical_max_power.
این تابع باید محدودهی بازدهی راکتور را برگرداند: "green"، "orange"، "red" یا "black".
Reactor.reactor_efficiency(200,50,15000)
# => "orange"
تمرین آخر شما شامل ساختن یک مکانیزم ایمن در برابر خرابی است تا از اضافهبار و ذوب هسته جلوگیری شود. این مکانیزم تعیین میکند که راکتور پایینتر، برابر یا بالاتر از آستانهی بحرانی ایدهآل است. سپس میتوان با وارد کردن (یا خارج کردن) میلههای کنترل در راکتور، میزان بحرانی بودن را افزایش، کاهش یا متوقف کرد.
متدی به اسم Reactor.fail_safe() را پیادهسازی کنید که ۳ پارامتر میگیرد: temperature برحسب کلوین، neutrons_produced_per_second و threshold؛ و یک کد وضعیت برای راکتور خروجی میدهد.
اگر temperature * neutrons_produced_per_second کمتر از ۹۰٪ مقدار threshold باشد، کد وضعیت "LOW" را خروجی بدهید؛ این کد نشان میدهد که برای تولید توان باید میلههای کنترل را خارج کرد.
اگر temperature * neutrons_produced_per_second در محدودهی مثبت یا منفی ۱۰٪ مقدار threshold باشد، راکتور در حالت بحرانی است و باید کد وضعیت "NORMAL" خروجی داده شود؛ این کد نشان میدهد که راکتور در وضعیت بهینه است و میلههای کنترل در موقعیت ایدهآل قرار دارند.
اگر temperature * neutrons_produced_per_second در محدودههای گفتهشده نباشد، راکتور در حال ذوب هسته است و باید کد وضعیت "DANGER" ارسال شود تا راکتور فوراً خاموش شود.
temperature = 1000
neutrons_produced_per_second = 30
threshold = 5000
Reactor.fail_safe(temperature, neutrons_produced_per_second, threshold)
# => "DANGER"