الثوابت باستخدام const
جزء من قسم البرمجة كائنية التوجه في رحلة Kotlin على Coddy. الدرس 14 من 57.
يُعلن const val عن ثابت وقت الترجمة: وهي قيمة يتم تثبيتها عند ترجمة البرنامج. ويُسمح باستخدامه في المستوى الأعلى من الملف وداخل object أو companion object، وفقط مع الأنواع الأساسية مثل Int وDouble وBoolean، وكذلك مع String:
const val MAX_PLAYERS = 4
class Lobby {
val players = mutableListOf<String>()
fun canStart() = players.size in MIN_PLAYERS..MAX_PLAYERS
companion object {
const val MIN_PLAYERS = 2
}
}داخل main:
val lobby = Lobby()
lobby.players += listOf("ada", "bo")
println(lobby.canStart())
println("${Lobby.MIN_PLAYERS}-$MAX_PLAYERS players")الناتج:
true
2-4 playersتُسمّى الثوابت باستخدام UPPER_SNAKE_CASE. تكون const أكثر صرامة من val: يجب معرفة القيمة من دون تشغيل أي كود، لذلك لا يُسمح باستدعاء دالة أو قائمة. كما أن val داخل كائن تكون مشتركة للقراءة فقط أيضًا، وتقبل أي قيمة:
const val GREETING = "Hello" // حرفية String
const val TIMEOUT_MS = 30 * 1000 // محسوبة من الحرفيات
// const val START = System.nanoTime() // خطأ: ليست ثابتة
// const val DAYS = listOf("Mon", "Tue") // خطأ: فقط الأنواع الأساسية و String
object Defaults {
val DAYS = listOf("Mon", "Tue") // قيمة val مشتركة للقراءة فقط
}يمكن للكائن المرافق أيضًا أن يحتفظ بحالة مشتركة قابلة للتغيير. تقرأ كل مثيلة الخاصية نفسها وتغيّرها، وهذا يناسب العدادات وذاكرات التخزين المؤقت. يحتفظ هذا الصنف بمثيلة واحدة لكل اسم، لذا فإن طلبها مرتين يعيد الكائن نفسه (يتحقق === من أن مرجعين يشيران إلى كائن واحد):
class Tile private constructor(val name: String) {
companion object {
private val cache = mutableMapOf<String, Tile>()
val created: Int
get() = cache.size
fun of(name: String) = cache.getOrPut(name) { Tile(name) }
}
}داخل main:
val a = Tile.of("grass")
val b = Tile.of("grass")
Tile.of("water")
println(a === b)
println(Tile.created)المخرجات:
true
2على المستوى الأعلى أم داخل الكائن المرافق؟ ينتمي الثابت أو الدالة على المستوى الأعلى إلى ملفه، ويُستخدم باسمه المجرّد في كل ملف من ملفات الحزمة. ضع الثابت داخل كائن مرافق عندما ينتمي إلى فئة واحدة: يكتب المستدعون Lobby.MIN_PLAYERS، وهذا يوضح مصدر القيمة، بينما يبقى private const val داخل تلك الفئة.
// Limits.kt
const val MAX_UPLOAD_MB = 25 // يُستخدم في كل مكان كـ MAX_UPLOAD_MB
// Lobby.kt
class Lobby {
companion object {
const val MIN_PLAYERS = 2 // يُستخدم كـ Lobby.MIN_PLAYERS
private const val ROOM_PREFIX = "L-" // فقط داخل Lobby
}
}التحدي
سهلأكمل الصنف Order(val item: String, val qty: Int). يحتوي الكائن المرافق له على الثابتين MAX_QTY = 10 وPREFIX = "ORD"، وعداد خاص لرقم الطلب التالي، والإجمالي المشترك للقراءة فقط totalItems، والعدد المحسوب count للطلبات التي تم إنشاؤها. تتطلب كتلة init كمية بين 1 وMAX_QTY مع الرسالة quantity must be 1-10 (المبنية من الثابت)، ثم تمنح الطلب معرّفه ORD-001 وORD-002 ... وتضيف كميته إلى totalItems. تُرجع label() القيمة ORD-001 tea x2.
يطبع الكود المقدم max per order: 10، ثم يقرأ السطرين tea 2 ويطبع التسمية أو رسالة الخطأ، وأخيرًا orders: 2, items: 5. الطلبات المرفوضة لا تستهلك رقمًا.
ضع الكود الخاص بك في Order.kt. يحتوي Main.kt على كود الإدخال/الإخراج المقدم ولا يمكن تعديله.
جرّب بنفسك
fun main() {
// كود الإدخال/الإخراج المُزوَّد: أبقِه كما هو
val input = generateSequence(::readLine).toList()
println("max per order: ${Order.MAX_QTY}")
for (line in input) {
val (item, qty) = line.split(" ")
try {
println(Order(item, qty.toInt()).label())
} catch (e: IllegalArgumentException) {
println(e.message)
}
}
println("orders: ${Order.count}, items: ${Order.totalItems}")
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1الفئات والكائنات
العمل مع الملفاتتعريف الفئاتالمنشئات الأساسيةكتل init والتحقق من الصحةالمنشئات الثانويةمراجعة - بطاقة المكتبة4الوراثة
الأصناف المفتوحة والأصناف الفرعيةتجاوز الأعضاءsuper والمنشئاتالأصناف المجرّدةمراجعة - دليل الموظفين3الكائنات والكائنات المرافقة
تعريفات الكائناتالكائنات المرافقةالثوابت باستخدام constتعبيرات الكائناتمراجعة - شباك التذاكرتدرّب بنفسك: Playground لـ Kotlin