دليل أسلوب Kotlin

يُعد هذا المستند بمثابة التعريف الكامل لمعايير ترميز Google لنظام Android لرمز المصدر في لغة برمجة 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 = // …
// Map.kt
fun <T, O> Set<T>.map(func: (T) -> O): List<O> = // …
fun <T, O> List<T>.map(func: (T) -> O): List<O> = // …
// extensions.kt
fun MyClass.process() = // …
fun MyResult.print() = // …

رموز خاصة

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

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

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

تسلسلات هروب خاصة

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

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

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

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

التركيبة

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

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

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

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

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

لا تستخدِم KDoc-style أو تعليقًا مؤلفًا من سطر واحد.

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

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

يتم وضع التعليقات التوضيحية التي تتضمن user-site target "file" بين أي تعليق في الرأس وإعلان الحزمة.

بيان الحزمة

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

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

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

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

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

نماذج بيانات المستوى الأعلى

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

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

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

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

المهم هو أن يستخدم كل ملف بعض الترتيب المنطقي، والذي يمكن للمسؤول عنه شرحه إذا طُلِب من ذلك. على سبيل المثال، لا تتم إضافة الدوال الجديدة عادةً إلى نهاية الملف، لأنّ ذلك سيؤدي إلى ترتيب "ترتيبًا زمنيًا" حسب تاريخ الإضافة، وهو ليس ترتيبًا منطقيًا.

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

يتبع ترتيب الأعضاء ضمن الفئة ما القواعد نفسها التي تتّبعها إشعارات المستوى الأعلى.

التنسيق

دعّامات

لا يُشترَط استخدام الأقواس مع فروع 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)
}

الوحدات الأساسية غير الفارغة

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

  • ليس هناك فاصل أسطر قبل القوس الافتتاحي.
  • فاصل سطر بعد قوس الفتح.
  • فاصل خط قبل قوس الإغلاق.
  • فاصل سطر بعد قوس الإغلاق، فقط إذا أنهى القوس المتعرّج عبارة أو أنه ينهي نص دالة أو دالة إنشائية أو فئة مسمّاة. على سبيل المثال، لا يكون هناك فاصل أسطر بعد القوس المتبوع بـ 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
  • أسطر الأوامر في تعليق قد يتم قصها ولصقها في واجهة أوامر

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

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

  • عند كسر سطر عند عامل التشغيل أو اسم الدالة infix، يأتي الفاصل بعد اسم العامل أو دالة infix.
  • عند كسر خط عند الرموز التالية التي "تشبه عامل التشغيل"، يأتي الفاصل قبل الرمز:
    • فاصل النقاط (.، ?.).
    • النقطتان الرأسيتان لمرجع العضو (::).
  • تظل الطريقة أو اسم دالة الإنشاء مرتبطًا بالقوس المفتوح (() الذي يليه.
  • تبقى الفاصلة (,) مرفقة بالرمز المميّز الذي يسبقها.
  • يظل سهم 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> 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.

أسماء الدوال

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

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

@Test fun pop_emptyStack() {
    // …
}

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

@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_JOINER = Joiner.on(',') // Joiner is immutable
val EMPTY_ARRAY = arrayOf()

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

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

يجب استخدام المعدِّل const للقيم الثابتة.

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

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

val variable = "var"
val nonConstScalar = "non-const"
val mutableCollection: MutableSet = 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? = null

val table: Map
    get() {
        if (_table == null) {
            _table = HashMap()
        }
        return _table ?: throw AssertionError()
    }

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

تتم تسمية كل متغير نوع بنمط من النمطين:

  • حرف كبير مفرد، اختياريًا، متبوعًا برقم واحد (مثل E، T، X، T2)
  • اسم بالصيغة المستخدمة للصفوف، متبوعًا بالحرف الكبير T (مثل RequestT، FooBarT)

حالة الجمل

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

يبدأ بصيغة النثر للاسم:

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

تجدر الإشارة إلى أنّه يتم غالبًا تجاهل حالة الكلمات الأصلية.

نموذج نثر صحيح غير صحيح
"طلب XML Http" XmlHttpRequest XMLHTTPRequest
"رقم تعريف العميل الجديد" newCustomerId newCustomerID
"ساعة إيقاف داخلية" 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، في الحالات التي لا يكون فيها أي شيء آخر جدير بالاهتمام هو "إرجاع الفعل".

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

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

لا يوجد KDoc دائمًا على طريقة تلغي طريقة Supertype.