این سند به عنوان تعریف کامل استانداردهای کدنویسی اندروید گوگل برای کد منبع در زبان برنامه نویسی 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" وجود دارد. برای بهبود قابلیت پیش بینی، از طرح زیر استفاده کنید.
با شکل نثر نام شروع می شود:
- عبارت را به ASCII ساده تبدیل کنید و هر آپستروف را حذف کنید. به عنوان مثال، "الگوریتم مولر" ممکن است به "الگوریتم مولر" تبدیل شود.
- این نتیجه را به کلمات، تقسیم بر روی فاصله و هر علامت نگارشی باقیمانده (معمولا خط تیره) تقسیم کنید. توصیه میشود: اگر کلمهای در حال حاضر دارای ظاهر معمولی شتر است، آن را به بخشهای تشکیلدهنده آن تقسیم کنید (مثلاً «AdWords» به «کلمات آگهی» تبدیل میشود). توجه داشته باشید که کلمه ای مانند "iOS" به خودی خود واقعاً در حالت شتر نیست. هر گونه قراردادی را نقض می کند، بنابراین این توصیه اعمال نمی شود.
- حالا همه چیز را کوچک کنید (از جمله حروف اختصاری)، سپس یکی از کارهای زیر را انجام دهید:
- اولین کاراکتر هر کلمه را بزرگ کنید تا حروف پاسکال به دست آید.
- اولین کاراکتر هر کلمه به جز اولین نویسه ای که حروف شتر را نشان می دهد، بزرگ کنید.
- در نهایت، همه کلمات را در یک شناسه واحد بپیوندید.
توجه داشته باشید که مخفف کلمات اصلی تقریباً به طور کامل نادیده گرفته شده است.
فرم نثر | صحیح | نادرست است |
---|---|---|
"درخواست 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 را لغو می کند وجود ندارد.