دليل أسلوب Kotlin

يعمل هذا المستند كتعريف كامل لمعايير ترميز Android من Google لرمز المصدر في لغة البرمجة Kotlin. يتم وصف ملف مصدر Kotlin بأنه متوافق مع "أسلوب Google Android" إذا كان يلتزم بالقواعد الواردة هنا فقط.

وكما هو الحال مع أدلة أساليب البرمجة الأخرى، لا تغطي المشاكل التي يتم تناولها المشاكل الجمالية المتعلقة بالتنسيق فحسب، بل تغطي أيضًا أنواعًا أخرى من الاتفاقيات أو معايير الترميز. ومع ذلك، يركّز هذا المستند بشكل أساسي على القواعد الثابتة التي نتبعها على مستوى العالم، ويتجنّب تقديم نصائح لا يمكن تطبيقها بوضوح (سواء من خلال البشر أو الأدوات).

تاريخ آخر تعديل: 2023-09-06

الملفات المصدر

يجب ترميز جميع الملفات المصدر بتنسيق UTF-8.

التسمية

إذا كان ملف المصدر يحتوي على فئة واحدة فقط من المستوى الأعلى، يجب أن يعكس اسم الملف الاسم مع مراعاة حالة الأحرف بالإضافة إلى الامتداد .kt. في ما عدا ذلك، إذا كان ملف المصدر يحتوي على عدة تعريفات على المستوى الأعلى، اختَر اسمًا يصف محتوى الملف، وطبِّق PascalCase (يمكن استخدام camelCase إذا كان اسم الملف بصيغة الجمع)، وأضِف الامتداد .kt.

// MyClass.kt
class MyClass { }

// Bar.kt
class Bar { }

fun Runnable.toBar(): Bar = Bar()

// Map.kt
fun <T, O> Set<T>.map(func: (T) -> O): List<O> = emptyList()
fun <T, O> List<T>.map(func: (T) -> O): List<O> = emptyList()

// extensions.kt
fun MyClass.process() = { /* ... */ }
fun MyResult.print() = { /* ... */ }

رموز خاصة

أحرف المسافة البيضاء

باستثناء تسلسل إنهاء السطر، حرف المسافة الأفقية ASCII (0x20) هو حرف المسافة البيضاء الوحيد الذي يظهر في أي مكان في ملف مصدر. يشير ذلك إلى ما يلي:

  • يتم تخطّي جميع أحرف المسافات البيضاء الأخرى في السلاسل الحرفية والحروف الحرفية.
  • لا يتم استخدام أحرف علامات التبويب للمسافة البادئة.

سلاسل إلغاء خاصة

بالنسبة إلى أي حرف يتضمّن تسلسلاً خاصًا للهروب (\b و\n و\r و\t و\' و\" و\\ و\$)، يتم استخدام هذا التسلسل بدلاً من تسلسل الهروب المقابل في Unicode (مثل \u000a).

أحرف بتنسيق غير ASCII

بالنسبة إلى الأحرف المتبقية غير ASCII، يتم استخدام حرف يونيكود الفعلي (مثل ) أو رمز إلغاء يونيكود المكافئ (مثل \u221e). يعتمد الاختيار فقط على ما يجعل التعليمات البرمجية أسهل في القراءة والفهم. لا يُنصح باستخدام رموز Unicode المخصّصة للأحرف القابلة للطباعة في أي مكان، ويُمنع منعًا باتًا استخدامها خارج السلاسل الحرفية والتعليقات.

مثال المناقشة
val unitAbbrev = "μs" الأفضل: واضح تمامًا حتى بدون تعليق.
val unitAbbrev = "\u03bcs" // μs سيئ: لا يوجد سبب لاستخدام حرف إلغاء مع حرف قابل للطباعة.
val unitAbbrev = "\u03bcs" ضعيف: لا يعرف القارئ ما هو هذا.
return "\ufeff" + content جيد: استخدِم رموز الإلغاء للأحرف غير القابلة للطباعة، وأضِف تعليقًا إذا لزم الأمر.

البنية

يتضمّن ملف .kt ما يلي، بالترتيب:

  • عنوان حقوق الطبع والنشر و/أو الترخيص (اختياري)
  • التعليقات التوضيحية على مستوى الملف
  • بيان الحزمة
  • عبارات الاستيراد
  • التعريفات على المستوى الأعلى

يفصل سطر فارغ واحد بالضبط بين كل قسم من هذه الأقسام.

إذا كان عنوان حقوق الطبع والنشر أو الترخيص ينتمي إلى الملف، يجب وضعه في الأعلى مباشرةً في تعليق متعدد الأسطر.

/*
 * Copyright 2017 Google, Inc.
 *
 * ...
 */
 

لا تستخدِم تعليقًا بأسلوب KDoc أو بأسلوب السطر الواحد.

/**
 * Copyright 2017 Google, Inc.
 *
 * ...
 */
// Copyright 2017 Google, Inc.
//
// ...

التعليقات التوضيحية على مستوى الملف

يتم وضع التعليقات التوضيحية التي تتضمّن الهدف use-site بين أي تعليق في العنوان وتعريف الحزمة.

بيان الحزمة

لا يخضع بيان الحزمة لأي حدّ أقصى لعدد الأعمدة ولا يتم أبدًا تضمين التفاف الأسطر فيه.

عبارات الاستيراد

يتم تجميع عبارات الاستيراد الخاصة بالفئات والدوال والسمات معًا في قائمة واحدة ويتم ترتيبها حسب ASCII.

لا يُسمح بعمليات الاستيراد باستخدام أحرف البدل (من أي نوع).

على غرار عبارة الحزمة، لا تخضع عبارات الاستيراد لحد أقصى لعدد الأعمدة، ولا يتم أبدًا تضمينها في أسطر متعددة.

تعريفات المستوى الأعلى

يمكن لملف .kt تعريف نوع واحد أو أكثر أو دوال أو سمات أو أسماء مستعارة للأنواع على مستوى أعلى.

يجب أن يركّز محتوى الملف على موضوع واحد. وتشمل الأمثلة على ذلك نوعًا عامًا واحدًا أو مجموعة من دوال الإضافة التي تنفّذ العملية نفسها على أنواع متعددة من المتلقّيات. يجب فصل التصريحات غير ذات الصلة في ملفات منفصلة، كما يجب تقليل التصريحات العلنية في ملف واحد.

لا يتم فرض أي قيود صريحة على عدد محتويات الملف أو ترتيبها.

عادةً ما تتم قراءة ملفات المصدر من الأعلى إلى الأسفل، ما يعني أنّ الترتيب، بشكل عام، يجب أن يوضّح أنّ التعريفات الأعلى ستساعد في فهم التعريفات الأبعد. قد تختار الملفات المختلفة ترتيب محتوياتها بشكل مختلف. وبالمثل، قد يحتوي ملف على 100 سمة، وآخر على 10 دوال، وثالث على فئة واحدة.

المهم هو أن يستخدم كل ملف ترتيبًا منطقيًا ما، ويمكن لمشرف الملف شرحه عند الطلب. على سبيل المثال، لا تتم إضافة وظائف جديدة بشكل اعتيادي إلى نهاية الملف، لأنّ ذلك سيؤدي إلى ترتيب &quot;زمني حسب تاريخ الإضافة&quot;، وهو ترتيب غير منطقي.

ترتيب أعضاء الصف

يخضع ترتيب الأعضاء داخل الفئة للقواعد نفسها التي تنطبق على التعريفات ذات المستوى الأعلى.

التنسيق

دعامات لتقويم الأسنان

لا يلزم استخدام أقواس مع فروع when وتعبيرات if التي لا تحتوي على أكثر من فرع else واحد والتي يمكن كتابتها في سطر واحد.

if (string.isEmpty()) return

val result =
    if (string.isEmpty()) DEFAULT_VALUE else string

when (value) {
    0 -> return
    // …
}

في ما عدا ذلك، تكون الأقواس المعقوفة مطلوبة لأي فرع من فروع if وfor وwhen وعبارات do وwhile وتعبيراتها، حتى عندما يكون النص فارغًا أو يحتوي على عبارة واحدة فقط.

if (string.isEmpty())
    return  // WRONG!

if (string.isEmpty()) {
    return  // Okay
}

if (string.isEmpty()) return  // WRONG
else doLotsOfProcessingOn(string, otherParametersHere)

if (string.isEmpty()) {
    return  // Okay
} else {
    doLotsOfProcessingOn(string, otherParametersHere)
}

المربّعات غير الفارغة

تتّبع الأقواس المتعرّجة نمط Kernighan وRitchie ("الأقواس المصرية") مع الكتل غير الفارغة والتركيبات الشبيهة بالكتل:

  • لا يجب وضع فاصل أسطر قبل القوس المفتوح.
  • فاصل أسطر بعد القوس المتعرّج المفتوح
  • فاصل أسطر قبل القوس المعقوف الأخير
  • يجب إضافة فاصل أسطر بعد قوس الإغلاق، فقط إذا كان هذا القوس ينهي عبارة أو ينهي نص دالة أو دالة إنشائية أو فئة مُسمّاة. على سبيل المثال، لا يوجد فاصل أسطر بعد القوس المعقوف إذا كان متبوعًا بـ else أو فاصلة.

return Runnable {
    while (condition()) {
        foo()
    }
}

return object : MyClass() {
    override fun foo() {
        if (condition()) {
            try {
                something()
            } catch (e: ProblemException) {
                recover()
            }
        } else if (otherCondition()) {
            somethingElse()
        } else {
            lastThing()
        }
    }
}

في ما يلي بعض الاستثناءات المتعلقة بفئات التعداد.

المربّعات الفارغة

يجب أن يكون البلوك الفارغ أو البلوك المشابه بتنسيق K&R.

try {
    doSomething()
} catch (e: Exception) {} // WRONG!

try {
    doSomething()
} catch (e: Exception) {
} // Okay

التعبيرات

يمكن حذف الأقواس فقط من جملة if/else شرطية مستخدَمة كتعبير، إذا كان التعبير بأكمله يتّسع لسطر واحد.

val value = if (string.isEmpty()) 0 else 1 // Okay

val value = if (string.isEmpty())  // WRONG!
    0
else
    1

val value = if (string.isEmpty()) { // Okay
    0
} else {
    1
}

المسافة البادئة

في كل مرة يتم فيها فتح كتلة جديدة أو بنية تشبه الكتلة، تزيد المسافة البادئة بمقدار أربع مسافات. عند انتهاء الكتلة، تعود المسافة البادئة إلى مستوى المسافة البادئة السابق. ينطبق مستوى المسافة البادئة على كلّ من الرمز والتعليقات في جميع أنحاء الكتلة.

عبارة واحدة لكل سطر

يتبع كل عبارة فاصل أسطر. لا يتم استخدام الفواصل المنقوطة.

لفّ السطر

يجب ألّا يتجاوز عدد أحرف الرمز 100 حرف في العمود. باستثناء ما هو مذكور أدناه، يجب أن يتم التفاف أي سطر يتجاوز هذا الحد، كما هو موضّح أدناه.

الاستثناءات:

  • الأسطر التي لا يمكن فيها الالتزام بحدّ عدد الأعمدة (مثل عنوان URL طويل في KDoc)
  • كشوفات حساب package وimport
  • أسطر الأوامر في تعليق يمكن قصه ولصقه في غلاف

أماكن الاستراحة

إنّ التوجيه الأساسي لتغليف الأسطر هو: تفضيل التقسيم على مستوى نحوي أعلى. أيضًا:

  • عندما يتم تقسيم سطر عند عامل تشغيل أو اسم دالة وسيطة، يكون التقسيم بعد عامل التشغيل أو اسم الدالة الوسيطة.
  • عندما يتم تقسيم سطر عند الرموز التالية التي تشبه عوامل التشغيل، يحدث التقسيم قبل الرمز:
    • فاصل النقطة (.، ?.)
    • نقطتان رأسيتان في مرجع عضو (::)
  • يبقى اسم الطريقة أو الدالة الإنشائية مرتبطًا بالقوس المفتوح (() الذي يليه.
  • تبقى الفاصلة (,) مرتبطة بالرمز المميّز الذي يسبقها.
  • يبقى سهم دالة lambda (->) مرتبطًا بقائمة الوسيطات التي تسبقه.

الدوال

عندما لا يتسع توقيع الدالة في سطر واحد، قسِّم كل تعريف مَعلمة إلى سطر منفصل. يجب أن تستخدم المَعلمات المحدّدة بهذا التنسيق مسافة بادئة واحدة (+4). يتم وضع قوس الإغلاق ()) ونوع الإرجاع في سطر منفصل بدون مسافة بادئة إضافية.

fun <T> Iterable<T>.joinToString(
    separator: CharSequence = ", ",
    prefix: CharSequence = "",
    postfix: CharSequence = ""
): String {
    // ...
}

دوال التعبير

عندما تحتوي الدالة على تعبير واحد فقط، يمكن تمثيلها على أنّها دالة تعبير.

override fun toString(): String {
    return "Hey"
}

override fun toString(): String = "Hey"

الخصائص

عندما لا يتناسب برنامج تهيئة الخاصية مع سطر واحد، يجب إدراج فاصل بعد علامة المساواة (=) واستخدام مسافة بادئة.

private val defaultCharset: Charset? =
    EncodingRegistry.getInstance().getDefaultCharsetForPropertiesFiles(file)

يجب أن تضع المواقع التي تحدّد الدالتَين get و/أو set كل دالة في سطر منفصل مع مسافة بادئة عادية (+4). يجب تنسيقها باستخدام القواعد نفسها المطبّقة على الدوال.

var directory: File? = null
    set(value) {
        // …
    }
يمكن أن تستخدم الخصائص للقراءة فقط بنية أقصر تتناسب مع سطر واحد.

val defaultExtension: String get() = "kt"

مسافة بيضاء

عمودي

يظهر سطر فارغ واحد:

  • بين الأعضاء المتتاليين في فئة: الخصائص، والدوال الإنشائية، والدوال، والفئات المتداخلة، وما إلى ذلك
    • استثناء: يمكن ترك سطر فارغ بين سمتَين متتاليتَين (لا يتضمّن أي رمز آخر بينهما). يتم استخدام أسطر فارغة من هذا النوع حسب الحاجة لإنشاء مجموعات منطقية من السمات وربط السمات بالسمة الأساسية، إذا كانت متوفرة.
    • استثناء: يتم تناول الأسطر الفارغة بين الثوابت المحدّدة أدناه.
  • بين العبارات، حسب الحاجة لتنظيم الرمز البرمجي في أقسام فرعية منطقية
  • اختياريًا قبل الجملة الأولى في الدالة، أو قبل العضو الأول في الفئة، أو بعد العضو الأخير في الفئة (لا ننصح بذلك ولا نثبطه).
  • على النحو المطلوب بموجب الأقسام الأخرى من هذا المستند (مثل قسم البنية).

يُسمح باستخدام أسطر فارغة متتالية متعددة، ولكن لا ننصح بذلك ولا يكون ذلك مطلوبًا أبدًا.

أفقي

بالإضافة إلى الأماكن التي تتطلّبها اللغة أو قواعد الأسلوب الأخرى، وباستثناء القيم الحرفية والتعليقات وKDoc، يظهر فراغ واحد من ASCII في الأماكن التالية فقط:

  • فصل أي كلمة محجوزة، مثل if أو for أو catch، عن قوس مفتوح (() يليها في ذلك السطر
    // WRONG!
    for(i in 0..1) {
    }
    // Okay
    for (i in 0..1) {
    }
  • فصل أي كلمة محجوزة، مثل else أو catch، عن قوس معقوف الإغلاق (}) الذي يسبقها في ذلك السطر
    // WRONG!
    }else {
    }
    // Okay
    } else {
    }
  • قبل أي قوس متعرّج مفتوح ({)
    // WRONG!
    if (list.isEmpty()){
    }
    // Okay
    if (list.isEmpty()) {
    }
  • على جانبي أي عامل ثنائي
    // WRONG!
    val two = 1+1
    // Okay
    val two = 1 + 1
    ينطبق ذلك أيضًا على الرموز التالية التي تشبه عوامل التشغيل:
    • السهم في تعبير lambda (->)
      // WRONG!
      ints.map { value->value.toString() }
      // Okay
      ints.map { value -> value.toString() }
    ولكن ليس:
    • نقطتَين رأسيتَين (::) في مرجع عضو
      // WRONG!
      val toString = Any :: toString
      // Okay
      val toString = Any::toString
    • فاصل النقطة (.)
      // WRONG
      it . toString()
      // Okay
      it.toString()
    • عامل النطاق (..)
      // WRONG
      for (i in 1 .. 4) {
        print(i)
      }
      // Okay
      for (i in 1..4) {
        print(i)
      }
  • قبل علامة النقطتين الرأسيتَين (:) فقط إذا تم استخدامها في تعريف فئة لتحديد فئة أساسية أو واجهات، أو عند استخدامها في عبارة where من أجل قيود عامة.
    // WRONG!
    class Foo: Runnable
    // Okay
    class Foo : Runnable
    // WRONG
    fun <T: Comparable> max(a: T, b: T)
    // Okay
    fun <T : Comparable<T>> max(a: T, b: T)
    // WRONG
    fun <T> max(a: T, b: T) where T: Comparable<T>
    // Okay
    fun <T> max(a: T, b: T) where T : Comparable<T> {}
  • بعد فاصلة (,) أو نقطتَين رأسيتَين (:)
    // WRONG!
    val oneAndTwo = listOf(1,2)
    // Okay
    val oneAndTwo = listOf(1, 2)
    // WRONG!
    class Foo :Runnable
    // Okay
    class Foo : Runnable
  • على جانبي الشرطتين المائلتين المزدوجتين (//) اللتين تبدأ بهما تعليقات نهاية السطر يُسمح هنا بإضافة مسافات متعددة، ولكن ليس مطلوبًا ذلك.
    // WRONG!
    var debugging = false//disabled by default
    // Okay
    var debugging = false // disabled by default

لا يتم تفسير هذه القاعدة على أنّها تتطلّب أو تحظر إضافة مساحة في بداية السطر أو نهايته، بل تتناول المساحة الداخلية فقط.

التركيبات المحدّدة

فئات التعداد

يمكن تنسيق تعداد بدون دوال وبدون توثيق للثوابت كسطر واحد.

enum class Answer { YES, NO, MAYBE }

عند وضع الثوابت في تعداد على أسطر منفصلة، لا يلزم وجود سطر فارغ بينها إلا في الحالة التي تحدد فيها نصًا.

enum class Answer {
    YES,
    NO,

    MAYBE {
        override fun toString() = """¯\_(ツ)_/¯"""
    }
}

بما أنّ فئات التعداد هي فئات، تنطبق جميع القواعد الأخرى الخاصة بتنسيق الفئات.

التعليقات التوضيحية

يتم وضع التعليقات التوضيحية الخاصة بالأعضاء أو الأنواع على أسطر منفصلة قبل العنصر الذي تمت إضافة التعليق التوضيحي إليه مباشرةً.

@Retention(SOURCE)
@Target(FUNCTION, PROPERTY_SETTER, FIELD)
annotation class Global

يمكن وضع التعليقات التوضيحية بدون وسيطات في سطر واحد.

@JvmField @Volatile
var disposable: Disposable? = null

عند توفّر تعليق توضيحي واحد فقط بدون وسيطات، يمكن وضعه على السطر نفسه الذي يتضمّن التعريف.

@Volatile var disposable: Disposable? = null

@Test fun selectAll() {
    // …
}

لا يمكن استخدام بنية @[...] إلا مع هدف موقع استخدام صريح، وفقط لدمج تعليقَين توضيحيَين أو أكثر بدون وسيطات في سطر واحد.

@field:[JvmStatic Volatile]
var disposable: Disposable? = null

أنواع الإرجاع/الخصائص الضمنية

إذا كان نص دالة التعبير أو أداة تهيئة الخاصية عبارة عن قيمة عددية أو كان من الممكن استنتاج نوع الإرجاع بوضوح من النص، يمكن حذفها.

override fun toString(): String = "Hey"
// becomes
override fun toString() = "Hey"
private val ICON: Icon = IconLoader.getIcon("/icons/kotlin.png")
// becomes
private val ICON = IconLoader.getIcon("/icons/kotlin.png")

عند كتابة مكتبة، احتفِظ بتعريف النوع الصريح عندما يكون جزءًا من واجهة برمجة التطبيقات العامة.

التسمية

تستخدِم المعرّفات أحرف ASCII وأرقامها فقط، وفي عدد قليل من الحالات الموضّحة أدناه، تستخدِم شُرطًا سفلية. وبالتالي، تتم مطابقة كل اسم معرّف صالح بالتعبير العادي \w+.

لا يتم استخدام البادئات أو اللاحقات الخاصة، مثل تلك الواردة في الأمثلة name_ وmName وs_name وkName، إلا في حالة السمات الأساسية (راجِع السمات الأساسية).

أسماء الحِزم

تكون أسماء الحِزم بأحرف صغيرة فقط، ويتم ربط الكلمات المتتالية معًا (بدون شُرط سفلية).

// Okay
package com.example.deepspace
// WRONG!
package com.example.deepSpace
// WRONG!
package com.example.deep_space

كتابة الأسماء

تُكتب أسماء الفئات بتنسيق PascalCase، وعادةً ما تكون أسماءً أو عبارات اسمية. على سبيل المثال، Character أو ImmutableList. قد تكون أسماء الواجهات أيضًا أسماءً أو عبارات اسمية (مثل List)، ولكن قد تكون أحيانًا صفات أو عبارات صفة (مثل Readable).

يتم تسمية فئات الاختبارات بدءًا باسم الفئة التي يتم اختبارها، وتنتهي بـ Test. على سبيل المثال، HashTest أو HashIntegrationTest.

أسماء الدوال

تُكتب أسماء الدوال بنمط camelCase، وعادةً ما تكون أفعالاً أو عبارات فعلية. على سبيل المثال، sendMessage أو stop.

يُسمح بظهور الشرطات السفلية في أسماء دوال الاختبار لفصل المكوّنات المنطقية للاسم.

@Test fun pop_emptyStack() {
    // …
}

الدوال التي تمّت إضافة التعليقات التوضيحية إليها باستخدام @Composable والتي تعرض Unit تكون بتنسيق PascalCase ويتمّ تسميتها كأسماء، كما لو كانت أنواعًا.

@Composable
fun NameTag(name: String) {
    // …
}

يجب ألا تحتوي أسماء الدوال على مسافات لأنّ ذلك غير متاح على بعض الأنظمة الأساسية (لا يتوافق مع Android بشكل كامل).

// WRONG!
fun `test every possible case`() {}
// OK
fun testEveryPossibleCase() {}

أسماء الثوابت

تستخدم أسماء الثوابت UPPER_SNAKE_CASE: جميع الأحرف الكبيرة، مع فصل الكلمات بشرطات سفلية. ولكن ما هي الثابتة بالضبط؟

الثوابت هي خصائص val بدون دالة get مخصّصة، ومحتواها غير قابل للتغيير، ولا يمكن رصد أي آثار جانبية لوظائفها. ويشمل ذلك الأنواع غير القابلة للتغيير والمجموعات غير القابلة للتغيير من الأنواع غير القابلة للتغيير، بالإضافة إلى القيم العددية والسلاسل إذا تم وضع علامة const عليها. إذا كان بإمكان أي من الحالات القابلة للملاحظة الخاصة بمثيل ما أن تتغير، لا يكون هذا المثيل ثابتًا. ولا يكفي مجرد التخطيط لعدم تغيير الكائن.

const val NUMBER = 5
val NAMES = listOf("Alice", "Bob")
val AGES = mapOf("Alice" to 35, "Bob" to 32)
val COMMA_JOINED = NAMES.joinToString(", ")
val EMPTY_ARRAY = arrayOf<SomeMutableType>()

وعادةً ما تكون هذه الأسماء عبارة عن أسماء أو عبارات اسمية.

لا يمكن تحديد القيم الثابتة إلا داخل object أو كتعريف على أعلى مستوى. يجب استخدام اسم غير ثابت للقيم التي تستوفي متطلبات الثبات ولكن تم تعريفها داخل class.

يجب أن تستخدم الثوابت التي تكون قيمًا عددية const المعدِّل.

الأسماء غير الثابتة

تُكتب الأسماء غير الثابتة بنمط camelCase. تنطبق هذه القواعد على سمات المثيل والسمات المحلية وأسماء المَعلمات.

val variable = "var"
val nonConstScalar = "non-const"
val mutableCollection: MutableSet<String> = HashSet()
val mutableElements = listOf(mutableInstance)
val mutableValues = mapOf("Alice" to mutableInstance, "Bob" to mutableInstance2)
val logger = Logger.getLogger(MyClass::class.java.name)
val nonEmptyArray = arrayOf("these", "can", "change")

وعادةً ما تكون هذه الأسماء عبارة عن أسماء أو عبارات اسمية.

السمات الداعمة

عند الحاجة إلى خاصية داعمة، يجب أن يتطابق اسمها تمامًا مع اسم الخاصية الحقيقية باستثناء أنّه يجب أن يكون مسبوقًا بشرطة سفلية.

private var _table: Map<String, Int>? = null

val table: Map<String, Int>
    get() {
        if (_table == null) {
            _table = HashMap()
        }
        return _table ?: throw AssertionError()
    }

كتابة أسماء المتغيّرات

يتم تسمية كل متغيّر نوع بأحد الأسلوبين التاليين:

  • حرف كبير واحد، يليه بشكل اختياري رقم واحد (مثل E أو T أو X أو T2)
  • اسم في النموذج مستخدَم للفئات، متبوعًا بالحرف الكبير T (مثل RequestT أو FooBarT)

تنسيق Camel Case

في بعض الأحيان، تتوفّر أكثر من طريقة معقولة لتحويل عبارة إنجليزية إلى حالة الجملة المختلطة، مثلاً عند استخدام اختصارات أو تركيبات غير عادية مثل "IPv6" أو "iOS". لتحسين إمكانية التوقّع، استخدِم المخطط التالي.

بدايةً من شكل الاسم النثري:

  1. حوِّل العبارة إلى ASCII عادي وأزِل أي علامات اقتباس. على سبيل المثال، قد تصبح عبارة "خوارزمية مولر" "خوارزمية مولر".
  2. قسِّم هذه النتيجة إلى كلمات، مع الفصل بينها باستخدام المسافات وأي علامات ترقيم متبقية (عادةً الشُرط). يُنصح بما يلي: إذا كانت أي كلمة تظهر بشكل تقليدي في حالة الجملة المختلطة في الاستخدام الشائع، قسِّمها إلى أجزائها المكوّنة (على سبيل المثال، تصبح كلمة "AdWords" "إعلانات Google"). تجدر الإشارة إلى أنّ كلمة مثل "iOS" ليست في حالة الجملة المختلطة في حد ذاتها، بل تتجاهل أي اصطلاح، لذا لا ينطبق هذا الاقتراح.
  3. الآن، حوِّل كل الأحرف إلى أحرف صغيرة (بما في ذلك الاختصارات)، ثم نفِّذ أحد الإجراءات التالية:
    • يتم تحويل الحرف الأول من كل كلمة إلى حرف كبير لإنشاء حالة Pascal.
    • يتم تحويل الحرف الأول من كل كلمة إلى حرف كبير باستثناء الكلمة الأولى، وذلك للحصول على حالة CamelCase.
  4. أخيرًا، ادمج كل الكلمات في معرّف واحد.

يُرجى العلم أنّه يتم تجاهل حالة الأحرف في الكلمات الأصلية بالكامل تقريبًا.

شكل النثر صحيح غير صحيح
‫XML Http Request XmlHttpRequest XMLHTTPRequest
"معرّف العميل الجديد" newCustomerId newCustomerID
"inner stopwatch" innerStopwatch innerStopWatch
"يتوافق مع الإصدار السادس من بروتوكول الإنترنت (IPv6) على أجهزة iOS" supportsIpv6OnIos supportsIPv6OnIOS
"أداة استيراد المحتوى من YouTube" YouTubeImporter YoutubeImporter*

(* مقبول، ولكن لا يُنصح به.)

الوثائق

التنسيق

يمكنك الاطّلاع على التنسيق الأساسي لكتل KDoc في هذا المثال:

/**
 * Multiple lines of KDoc text are written here,
 * wrapped normally…
 */
fun method(arg: String) {
    // …
}

...أو في هذا المثال المكوّن من سطر واحد:

/** An especially short bit of KDoc. */

ويكون النموذج الأساسي مقبولاً دائمًا. يمكن استبدال النموذج المكوّن من سطر واحد عندما يمكن أن يتسع كامل قسم KDoc (بما في ذلك علامات التعليقات) في سطر واحد. يُرجى العِلم أنّ هذا ينطبق فقط في حال عدم توفّر علامات حظر، مثل @return.

الفقرات

يظهر سطر فارغ واحد، أي سطر يحتوي فقط على علامة النجمة البادئة المحاذية (*)، بين الفقرات وقبل مجموعة علامات الفقرات إذا كانت متوفرة.

علامات الحظر

تظهر أي من "علامات الحظر" العادية المستخدَمة بالترتيب @constructor و@receiver و@param و@property و@return و@throws و@see، ولا تظهر هذه العلامات أبدًا مع وصف فارغ. عندما لا تتسع علامة الحظر في سطر واحد، يتم ترك مسافة بادئة بمقدار 4 مسافات في أسطر المتابعة من موضع @.

مقتطف الملخّص

يبدأ كل جزء من KDoc بملخّص موجز. هذه السلسلة النصية مهمة جدًا، فهي الجزء الوحيد من النص الذي يظهر في سياقات معيّنة، مثل فهارس الفئات والطرق.

هذه عبارة غير كاملة، أي عبارة اسمية أو فعلية، وليست جملة كاملة. لا يبدأ المقتطف بـ "A `Foo` is a..." أو "This method returns..."، كما أنّه ليس بالضرورة أن يشكّل جملة أمرية كاملة مثل "Save the record."، ولكن يتم كتابة المقتطف بحرف كبير ويتم وضع علامات الترقيم فيه كما لو كان جملة كاملة.

الاستخدام

على الأقل، يكون KDoc متوفّرًا لكل نوع public، ولكل عضو public أو protected من هذا النوع، مع بعض الاستثناءات الموضّحة أدناه.

استثناء: الدوال الواضحة

إنّ KDoc اختيارية للدوال "البسيطة والواضحة"، مثل getFoo والسمات، مثل foo، في الحالات التي لا يوجد فيها أي شيء آخر يستحق الذكر سوى "إرجاع foo".

ولا يجوز الاستناد إلى هذا الاستثناء لتبرير إغفال معلومات ذات صلة قد يحتاج القارئ العادي إلى معرفتها. على سبيل المثال، إذا كانت لديك دالة باسم getCanonicalName أو سمة باسم canonicalName، لا تحذف مستنداتها (بحجة أنّها ستتضمّن /** Returns the canonical name. */ فقط) إذا كان القارئ العادي لا يعرف معنى مصطلح "الاسم الأساسي".

الاستثناء: عمليات الإلغاء

لا يتوفّر KDoc دائمًا في طريقة تتجاوز طريقة نوع فائق.