המסמך הזה הוא ההגדרה המלאה של תקני הקידוד של Google ל-Android עבור קוד מקור בשפת התכנות Kotlin. קובץ מקור של Kotlin מתואר כקובץ בסגנון Google Android אם ורק אם הוא עומד בכללים שמופיעים כאן.
בדומה למדריכים אחרים לסגנון תכנות, הבעיות שמפורטות כאן לא קשורות רק לבעיות אסתטיות של פורמט, אלא גם לסוגים אחרים של מוסכמות או תקני קידוד. עם זאת, המסמך הזה מתמקד בעיקר בכללים הברורים והמחייבים שאנחנו פועלים לפיהם באופן אוניברסלי, ולא כולל עצות שלא ניתן לאכוף בבירור (בין אם על ידי אדם או כלי).
קובצי מקור
כל קובצי המקור צריכים להיות בקידוד 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) הוא תו הרווח היחיד שמופיע בכל מקום בקובץ מקור. המשמעות היא:
- כל שאר התווים שיוצרים רווחים במחרוזות ובליטרלים של תווים מסומנים בתווי בריחה (escape).
- לא משתמשים בתווי Tab להזחה.
רצפי בריחה מיוחדים
לכל תו שיש לו רצף בריחה מיוחד (\b, \n, \r, \t, \', \", \\ ו-\$), נעשה שימוש ברצף הזה ולא ברצף הבריחה המתאים של Unicode (לדוגמה, \u000a).
תווים שאינם ASCII
לגבי שאר התווים שהם לא ASCII, משתמשים בתו Unicode בפועל
(למשל, ∞) או בתו בריחה (escape) מקביל של Unicode (למשל, \u221e).
הבחירה תלויה רק במה שיגרום לקוד להיות קל יותר לקריאה ולהבנה.
לא מומלץ להשתמש בתווי escape של Unicode לתווים שניתנים להדפסה בכל מיקום, ולא מומלץ להשתמש בהם מחוץ למחרוזות מילוליות ולתגובות.
| דוגמה | דיון |
|---|---|
val unitAbbrev = "μs" |
הכי טוב: ברור לחלוטין גם בלי תגובה. |
val unitAbbrev = "\u03bcs" // μs |
גרוע: אין סיבה להשתמש בתו בריחה עם תו שאפשר להדפיס. |
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, 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 and Ritchie (סוגריים מצריים) עבור בלוקים לא ריקים ומבנים דמויי בלוקים:
- אין מעבר שורה לפני הסוגר המסולסל הפותח.
- מעבר שורה אחרי הסוגר המסולסל הפותח.
- מעבר שורה לפני הסוגר המסולסל הסוגר.
- מעבר שורה אחרי הסוגר המסולסל הסוגר, רק אם הסוגר הזה מסיים הצהרה או מסיים את הגוף של פונקציה, של constructor או של מחלקה בעלת שם.
לדוגמה, אין מעבר שורה אחרי הסוגר המסולסל אם אחריו מופיע
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 classes.
בלוקים ריקים
בלוק ריק או מבנה דמוי בלוק צריך להיות בסגנון 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"
רווח לבן
אנכי
מופיעה שורה ריקה אחת:
- בין חברים עוקבים בכיתה: מאפיינים, בנאים,
פונקציות, כיתות מקוננות וכו'.
- חריג: אפשר להשאיר שורה ריקה בין שני נכסים עוקבים (אם אין קוד אחר ביניהם). שורות ריקות כאלה משמשות לפי הצורך כדי ליצור קיבוצים לוגיים של נכסים ולשייך נכסים לנכס הבסיס שלהם, אם קיים.
- חריג: שורות ריקות בין קבועי 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
- החץ בביטוי 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) }
- החץ בביטוי Lambda (
-
לפני נקודתיים (
:) רק אם משתמשים בהן בהצהרת מחלקה כדי לציין מחלקת בסיס או ממשקים, או אם משתמשים בהן בסעיף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)
אפשר לעצב 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 הן בפורמט 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
modifier.
שמות לא קבועים
שמות לא קבועים נכתבים ב-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() }
הקלדת שמות של משתנים
לכל משתנה מסוג type יש שם באחד משני הסגנונות הבאים:
- אות גדולה אחת, שאחריה יכול להיות מספר אחד (למשל
E,T,X,T2) - שם בטופס שמשמש לכיתות, ואחריו האות הגדולה
T(למשלRequestT,FooBarT)
קאמל קייס
לפעמים יש יותר מדרך סבירה אחת להמיר ביטוי באנגלית ל-Camel Case, למשל כשמופיעים ראשי תיבות או מבנים לא רגילים כמו IPv6 או iOS. כדי לשפר את יכולת החיזוי, מומלץ להשתמש בסכימה הבאה.
מתחילים עם השם בצורת פרוזה:
- ממירים את הביטוי ל-ASCII פשוט ומסירים את כל הגרשיים. לדוגמה, 'האלגוריתם של מילר' יכול להפוך ל-'האלגוריתם של מילר'.
- מחלקים את התוצאה למילים, ומפצלים לפי רווחים וסימני פיסוק שנותרו (בדרך כלל מקפים). מומלץ: אם מילה כלשהי כבר מופיעה בשימוש הנפוץ בפורמט camel-case, צריך לפצל אותה לחלקים שמרכיבים אותה (לדוגמה, AdWords הופך ל-ad words). שימו לב שמילה כמו iOS לא באמת מופיעה בפורמט camel-case; היא לא עומדת באף מוסכמה, ולכן ההמלצה הזו לא רלוונטית.
- עכשיו צריך להפוך את כל האותיות לקטנות (כולל ראשי תיבות), ואז לבצע אחת מהפעולות הבאות:
- האות הראשונה של כל מילה תהיה באותיות רישיות, כדי ליצור PascalCase.
- הפונקציה משנה את האות הראשונה של כל מילה לאות גדולה, מלבד המילה הראשונה, כדי ליצור אותיות קטנות וגדולות לסירוגין.
- לבסוף, מאחדים את כל המילים למזהה אחד.
שימו לב שהרישיות של המילים המקוריות כמעט ולא משנה.
| טופס פרוזה | תקין | שגוי |
|---|---|---|
| "XML Http Request" | XmlHttpRequest |
XMLHTTPRequest |
| "new customer ID" (מספר לקוח חדש) | newCustomerId |
newCustomerID |
| 'שעון העצר הפנימי' | innerStopwatch |
innerStopWatch |
| "supports IPv6 on iOS" (תמיכה ב-IPv6 ב-iOS) | supportsIpv6OnIos |
supportsIPv6OnIOS |
| YouTube importer (כלי לייבוא מ-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 לא תמיד מופיעה בשיטה שמבטלת שיטה של סוג-על.