راهنمای سبک کاتلین

این سند به عنوان تعریف کامل استانداردهای کدنویسی اندروید گوگل برای کد منبع در زبان برنامه نویسی Kotlin است. یک فایل منبع Kotlin در صورتی در Google Android Style توصیف می‌شود که قوانین موجود در اینجا را رعایت کند.

مانند سایر راهنماهای سبک برنامه نویسی، موضوعات تحت پوشش نه تنها مسائل زیبایی شناختی قالب بندی، بلکه انواع دیگر قراردادها یا استانداردهای کدنویسی را نیز در بر می گیرند. با این حال، این سند اساساً بر قوانین سخت و سریعی که ما به طور جهانی از آنها پیروی می کنیم تمرکز دارد و از دادن توصیه هایی که به وضوح قابل اجرا نیستند (خواه توسط انسان یا ابزار) اجتناب می کند.

آخرین به روز رسانی: 06-09-2023

فایل های منبع

همه فایل های منبع باید به صورت 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) تنها کاراکتر فضای خالی است که در هر جایی از فایل منبع ظاهر می شود. این به این معنی است که:

  • تمام نویسه‌های فضای خالی دیگر در رشته‌ها و حروف نویسه‌ها حذف می‌شوند.
  • کاراکترهای برگه برای تورفتگی استفاده نمی شوند.

سکانس های فرار ویژه

برای هر کاراکتری که دارای یک دنباله فرار خاص است ( \b ، \n ، \r ، \t ، \' ، \" ، \\ و \$ ) از آن دنباله به جای یونیکد مربوطه استفاده می شود (مثلا \u000a ) فرار

کاراکترهای غیر ASCII

برای نویسه‌های غیرASCII باقی‌مانده، از نویسه یونیکد واقعی (مثلاً ) یا فرار یونیکد معادل (مثلاً \u221e ) استفاده می‌شود. انتخاب فقط به این بستگی دارد که کدام کد را برای خواندن و درک راحت‌تر می‌کند. فرار یونیکد برای کاراکترهای قابل چاپ در هر مکانی ممنوع است و به شدت در خارج از لفظ رشته و نظرات ممنوع است.

مثال بحث
val unitAbbrev = "μs" بهترین: کاملا واضح حتی بدون نظر.
val unitAbbrev = "\u03bcs" // μs ضعیف: دلیلی برای استفاده از escape با کاراکتر قابل چاپ وجود ندارد.
val unitAbbrev = "\u03bcs" ضعیف: خواننده نمی داند این چیست.
return "\ufeff" + content خوب: برای کاراکترهای غیر قابل چاپ از escape استفاده کنید و در صورت لزوم نظر دهید.

ساختار

یک فایل .kt به ترتیب شامل موارد زیر است:

  • عنوان حق چاپ و/یا مجوز (اختیاری)
  • حاشیه نویسی در سطح فایل
  • بیانیه بسته
  • بیانیه های وارداتی
  • اعلامیه های سطح بالا

دقیقاً یک خط خالی هر یک از این بخش ها را جدا می کند.

اگر سرصفحه حق چاپ یا مجوز در فایل تعلق دارد، باید در یک نظر چند خطی در بالای صفحه قرار گیرد.

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

از نظرات به سبک KDoc یا تک خطی استفاده نکنید.

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

حاشیه نویسی در سطح فایل

حاشیه نویسی با هدف سایت استفاده از "فایل" بین هر نظر سرصفحه و اعلامیه بسته قرار می گیرد.

بیانیه بسته

بیانیه بسته مشمول هیچ محدودیت ستونی نیست و هرگز به صورت خطی بسته نمی شود.

بیانیه های وارداتی

دستورات وارد کردن برای کلاس ها، توابع و ویژگی ها در یک لیست واحد با هم گروه بندی می شوند و 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 branch, do , and 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()
        }
    }
}

چند استثنا برای کلاس های enum در زیر آورده شده است.

بلوک های خالی

یک بلوک خالی یا ساختار بلوک مانند باید به سبک 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 می آید.
  • هنگامی که یک خط در نمادهای "عملگر مانند" زیر شکسته می شود، شکست قبل از نماد می آید:
    • جداکننده نقطه ( . , ?. ).
    • دو دونقطه مرجع یک عضو ( :: :).
  • یک نام متد یا سازنده به پرانتز باز ( ( ) که به دنبال آن است پیوست می ماند.
  • یک کاما ( , ) به نشانه ای که قبل از آن قرار دارد متصل می ماند.
  • یک فلش لامبدا ( -> ) به لیست آرگومان های قبل از آن پیوست می ماند.

توابع

هنگامی که یک امضای تابع در یک خط قرار نمی گیرد، هر اعلان پارامتر را در خط خودش بشکنید. پارامترهای تعریف شده در این قالب باید از یک تورفتگی (+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"

فضای خالی

عمودی

یک خط خالی ظاهر می شود:

  • بین اعضای متوالی یک کلاس: ویژگی ها، سازنده ها، توابع، کلاس های تو در تو و غیره.
    • استثنا: یک خط خالی بین دو ویژگی متوالی (بدون هیچ کد دیگری بین آنها) اختیاری است. چنین خطوط خالی در صورت نیاز برای ایجاد گروه بندی منطقی از ویژگی ها و مرتبط کردن خواص با ویژگی پشتیبان آنها، در صورت وجود، استفاده می شود.
    • استثنا: خطوط خالی بین ثابت های enum در زیر پوشش داده شده است.
  • بین عبارات، در صورت نیاز برای سازماندهی کد در زیربخش های منطقی.
  • به صورت اختیاری قبل از اولین عبارت در یک تابع، قبل از اولین عضو یک کلاس، یا بعد از آخرین عضو یک کلاس (نه تشویق و نه دلسرد).
  • همانطور که در بخش های دیگر این سند (مانند بخش ساختار ) نیاز است.

چند خط خالی متوالی مجاز است، اما تشویق یا هرگز مورد نیاز نیست.

افقی

فراتر از جایی که زبان یا قوانین سبک دیگر لازم است، و جدای از حروف الفظی، نظرات و 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
    این همچنین برای نمادهای "عملگر مانند" زیر اعمال می شود:
    • فلش در عبارت لامبدا ( -> ).
      // 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

یک enum بدون توابع و هیچ سندی روی ثابت‌های آن ممکن است به صورت اختیاری به صورت یک خط واحد قالب‌بندی شود.

enum class Answer { YES, NO, MAYBE }

وقتی ثابت‌های یک enum روی خطوط جداگانه قرار می‌گیرند، یک خط خالی بین آن‌ها لازم نیست، مگر در مواردی که بدنه را تعریف می‌کنند.

enum class Answer {
    YES,
    NO,

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

از آنجایی که کلاس های enum کلاس هستند، تمام قوانین دیگر برای قالب بندی کلاس ها اعمال می شود.

حاشیه نویسی ها

حاشیه نویسی اعضا یا نوع در خطوط جداگانه بلافاصله قبل از ساختار مشروح قرار می گیرد.

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

حاشیه نویسی بدون آرگومان را می توان در یک خط قرار داد.

@JvmField @Volatile
var disposable: Disposable? = null

وقتی فقط یک حاشیه نویسی بدون آرگومان وجود دارد، ممکن است در همان خط اعلان قرار گیرد.

@Volatile var disposable: Disposable? = null

@Test fun selectAll() {
    // …
}

نحو @[...] فقط می‌توان با یک هدف سایت استفاده صریح و فقط برای ترکیب 2 یا چند حاشیه‌نویسی بدون آرگومان در یک خط استفاده کرد.

@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")

هنگام نوشتن یک کتابخانه، اعلان نوع صریح را زمانی که بخشی از API عمومی است حفظ کنید.

نامگذاری

شناسه‌ها فقط از حروف و ارقام 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 را برمی گرداند، 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<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 )

مورد شتر

گاهی اوقات بیش از یک راه معقول برای تبدیل یک عبارت انگلیسی به حالت شتر وجود دارد، مانند زمانی که کلمات اختصاری یا ساختارهای غیرعادی مانند "IPv6" یا "iOS" وجود دارد. برای بهبود قابلیت پیش بینی، از طرح زیر استفاده کنید.

با شکل نثر نام شروع می شود:

  1. عبارت را به ASCII ساده تبدیل کنید و هر آپستروف را حذف کنید. به عنوان مثال، "الگوریتم مولر" ممکن است به "الگوریتم مولر" تبدیل شود.
  2. این نتیجه را به کلمات، تقسیم بر روی فاصله و هر علامت نگارشی باقیمانده (معمولا خط تیره) تقسیم کنید. توصیه می‌شود: اگر کلمه‌ای در حال حاضر دارای ظاهر معمولی شتر است، آن را به بخش‌های تشکیل‌دهنده آن تقسیم کنید (مثلاً «AdWords» به «کلمات آگهی» تبدیل می‌شود). توجه داشته باشید که کلمه ای مانند "iOS" به خودی خود واقعاً در حالت شتر نیست. هر گونه قراردادی را نقض می کند، بنابراین این توصیه اعمال نمی شود.
  3. حالا همه چیز را کوچک کنید (از جمله حروف اختصاری)، سپس یکی از کارهای زیر را انجام دهید:
    • اولین کاراکتر هر کلمه را بزرگ کنید تا حروف پاسکال به دست آید.
    • اولین کاراکتر هر کلمه به جز اولین نویسه ای که حروف شتر را نشان می دهد، بزرگ کنید.
  4. در نهایت، همه کلمات را در یک شناسه واحد بپیوندید.

توجه داشته باشید که مخفف کلمات اصلی تقریباً به طور کامل نادیده گرفته شده است.

فرم نثر صحیح نادرست است
"درخواست XML Http" XmlHttpRequest XMLHTTPRequest
"شناسه مشتری جدید" newCustomerId newCustomerID
"کرنومتر داخلی" innerStopwatch innerStopWatch
"پشتیبانی از IPv6 در iOS" supportsIpv6OnIos supportsIPv6OnIOS
"وارد کننده یوتیوب" 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 را لغو می کند وجود ندارد.