เอกสารนี้เป็นคำจำกัดความที่สมบูรณ์ของมาตรฐานการเขียนโค้ด Android ของ Google สำหรับซอร์สโค้ดในภาษาการเขียนโปรแกรม Kotlin ไฟล์แหล่งที่มา Kotlin อธิบายว่าอยู่ใน Google Android Style ก็ต่อเมื่อไฟล์ดังกล่าวเป็นไปตามกฎในที่นี้เท่านั้น
เช่นเดียวกับคู่มือสไตล์การจัดโปรแกรมอื่นๆ ปัญหาที่กล่าวถึงไม่ได้ครอบคลุมเพียงปัญหาด้านความสวยงามของการจัดรูปแบบเท่านั้น แต่ยังรวมถึงแบบแผนหรือมาตรฐานการเขียนโค้ดประเภทอื่นๆ ด้วย อย่างไรก็ตาม เอกสารนี้มุ่งเน้นไปที่กฎที่เคร่งครัดและเข้มงวดเป็นหลักซึ่งเราปฏิบัติตามในระดับสากล และหลีกเลี่ยงการให้คำแนะนำที่ไม่สามารถบังคับใช้ได้อย่างชัดเจน (ไม่ว่าจะดำเนินการโดยมนุษย์หรือเครื่องมือ)
ไฟล์ต้นฉบับ
ไฟล์ต้นฉบับทั้งหมดต้องเข้ารหัสเป็น 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) เป็นอักขระช่องว่างเพียงตัวเดียวที่ปรากฏในที่ใดก็ได้ในไฟล์ต้นฉบับ ซึ่งหมายความว่า
- อักขระช่องว่างอื่นๆ ทั้งหมดในสตริงและลิเทอรัลอักขระจะถูก Escape
- ทั้งนี้ อักขระของแท็บไม่ใช้เพื่อการเยื้อง
ลำดับหลีกพิเศษ
สำหรับอักขระที่มีลำดับหลีกพิเศษ
(\b, \n, \r, \t, \', \", \\ และ \$)
จะใช้ลำดับดังกล่าวแทน Unicode ที่เกี่ยวข้อง
(เช่น \u000a) Escape
อักขระที่ไม่ใช่ ASCII
สำหรับอักขระที่ไม่ใช่ ASCII ที่เหลือ อักขระ Unicode จริง
(เช่น ∞) หรือ Escape Unicode ที่เทียบเท่า (เช่น \u221e)
ตัวเลือกจะขึ้นอยู่กับว่าสิ่งใดที่สร้างโค้ด
อ่านและทำความเข้าใจได้ง่ายขึ้น
ไม่สนับสนุนอักขระหลีก Unicode สำหรับอักขระที่พิมพ์ได้ในตำแหน่งต่างๆ และ
เป็นสิ่งที่ไม่แนะนำอย่างยิ่งเมื่ออยู่นอกคลังสตริงและความคิดเห็น
| ตัวอย่าง | แลกเปลี่ยนความคิดเห็น |
|---|---|
val unitAbbrev = "μs" |
ดีที่สุด: ชัดเจนที่สุดแม้จะไม่มีความคิดเห็น |
val unitAbbrev = "\u03bcs" // μs |
แย่: ไม่มีเหตุผลที่จะใช้ Escape กับอักขระที่พิมพ์ได้ |
val unitAbbrev = "\u03bcs" |
แย่: ผู้อ่านไม่ทราบว่าสิ่งนี้คืออะไร |
return "\ufeff" + content |
ดี: ใช้การหลีกสำหรับอักขระที่พิมพ์ไม่ได้ และแสดงความคิดเห็นหากจำเป็น |
โครงสร้าง
ไฟล์ .kt ประกอบด้วยรายการต่อไปนี้ตามลําดับ
- หัวข้อเกี่ยวกับลิขสิทธิ์และ/หรือใบอนุญาต (ไม่บังคับ)
- คำอธิบายประกอบระดับไฟล์
- ใบแจ้งยอดแพ็กเกจ
- นำเข้าใบแจ้งยอด
- การประกาศระดับบนสุด
จะมีบรรทัดว่าง 1 บรรทัดคั่นแต่ละส่วน
ลิขสิทธิ์ / ใบอนุญาต
หากมีส่วนหัวลิขสิทธิ์หรือใบอนุญาตอยู่ในไฟล์ คุณควรใส่ส่วนหัวดังกล่าวที่ด้านบนสุดในความคิดเห็นแบบหลายบรรทัด
/* * Copyright 2017 Google, Inc. * * ... */
อย่าใช้รูปแบบ KDoc หรือความคิดเห็นแบบบรรทัดเดียว
/** * Copyright 2017 Google, Inc. * * ... */
// Copyright 2017 Google, Inc. // // ...
คำอธิบายประกอบระดับไฟล์
คำอธิบายประกอบที่มีคำว่า "ไฟล์" เป้าหมายการใช้เว็บไซต์ จะวางอยู่ระหว่างความคิดเห็นส่วนหัวและการประกาศแพ็กเกจ
ใบแจ้งยอดแพ็กเกจ
คำสั่งแพ็กเกจไม่ได้อยู่ภายใต้ขีดจำกัดของคอลัมน์ใดๆ และไม่มีการขึ้นบรรทัดใหม่
นำเข้าใบแจ้งยอด
ระบบจะจัดกลุ่มคำสั่งนำเข้าสำหรับคลาส ฟังก์ชัน และพร็อพเพอร์ตี้ไว้ด้วยกันในรายการเดียวและจัดเรียง ASCII แล้ว
ไม่อนุญาตการนำเข้าไวลด์การ์ด (ทุกประเภท)
เช่นเดียวกับคำสั่งแพ็กเกจ คำสั่งการนำเข้าไม่อยู่ภายใต้ และไม่มีการขึ้นบรรทัดใหม่เลย
การประกาศระดับบนสุด
ไฟล์ .kt สามารถประกาศประเภท ฟังก์ชัน พร็อพเพอร์ตี้ หรือประเภทอย่างน้อย 1 รายการ
ชื่อแทนระดับบนสุด
เนื้อหาของไฟล์ควรมุ่งเน้นธีมเดียว ตัวอย่างของสิ่งนี้ จะเป็นสาธารณะประเภทเดียว หรือชุดฟังก์ชันส่วนขยายที่ประมวลผล การดำเนินการเดียวกันบนตัวรับสัญญาณหลายประเภท การประกาศที่ไม่เกี่ยวข้องควรมีลักษณะดังนี้ แยกเป็นไฟล์ของตัวเองและการประกาศสาธารณะภายในไฟล์เดียว ควรลดขนาดลง
ไม่ได้จำกัดหมายเลขหรือลำดับของเนื้อหาของ ไฟล์
ไฟล์ต้นฉบับมักจะอ่านจากบนลงล่าง หมายความว่าลำดับใน ควรสะท้อนให้เห็นว่าการประกาศในอันดับสูงขึ้นจะเป็นการบอก เข้าใจได้ลึกลงไปอีก ไฟล์ที่แตกต่างกันอาจเลือกจัดเรียงได้ เนื้อหาต่างกันไป ในทำนองเดียวกัน ไฟล์ 1 ไฟล์อาจประกอบด้วยพร็อพเพอร์ตี้ 100 รายการ ฟังก์ชันอื่นๆ อีก 10 รายการ และฟังก์ชันอีก 1 คลาส
สิ่งที่สำคัญคือแต่ละไฟล์ใช้ลำดับเชิงตรรกะบาง ผู้ดูแลอธิบายได้หากมีการถาม ตัวอย่างเช่น ฟังก์ชันใหม่ไม่ใช่แค่ ต่อท้ายไฟล์เป็นประจำ เพราะจะทำให้ "ตามลำดับเวลา ตามวันที่ที่เพิ่ม" ซึ่งไม่ใช่การเรียงลำดับเชิงตรรกะ
การจัดลำดับสมาชิกในชั้นเรียน
ลำดับของสมาชิกในชั้นเรียนจะเป็นไปตามกฎเดียวกับระดับบนสุด ประกาศ
การจัดรูปแบบ
เหล็กดัดฟัน
ไม่จำเป็นต้องใส่วงเล็บปีกกาสำหรับ Branch ของ when และนิพจน์ if
ที่มี Branch ของ else ไม่เกิน 1 สาขา และอยู่ในบรรทัดเดียว
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() } } }
ข้อยกเว้นบางประการสำหรับ คลาส 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 }
การเยื้อง
แต่ละครั้งที่มีการเปิดบล็อกหรือโครงสร้างที่คล้ายบล็อกใหม่ การเยื้องจะเพิ่มขึ้น 4 ช่องว่าง เมื่อสิ้นสุดการบล็อก การเยื้องจะกลับไปที่ระดับการเยื้องก่อนหน้า ระดับการเยื้องจะใช้กับทั้งโค้ดและความคิดเห็นตลอดทั้งบล็อก
หนึ่งข้อความต่อบรรทัด
ตามด้วยการขึ้นบรรทัดใหม่แต่ละข้อความ ไม่ใช้อัฒภาค
การตัดบรรทัด
รหัสมีคอลัมน์ได้ไม่เกิน 100 อักขระ บรรทัดใดๆ ที่จะเกินขีดจำกัดนี้จะต้องถูกล้อมรอบบรรทัด ดังที่อธิบายด้านล่าง ยกเว้นตามที่ระบุไว้ด้านล่าง
ข้อยกเว้น:
- บรรทัดที่ไม่สามารถปฏิบัติตามขีดจํากัดของคอลัมน์ (เช่น URL แบบยาวใน KDoc)
- ใบแจ้งยอด
packageและimport - บรรทัดคำสั่งในความคิดเห็นที่อาจถูกตัดและวางลงใน Shell
จุดที่แบ่งได้
คำสั่งที่สำคัญที่สุดของการตัดบรรทัดคือต้องการแตกที่ระดับไวยากรณ์ที่สูงขึ้น นอกจากนี้ การโอนช่องยังมีผลในด้านต่างๆ ต่อไปนี้
- เมื่อมีบรรทัดแยกที่โอเปอเรเตอร์หรือชื่อฟังก์ชัน 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"
เว้นวรรค
ประเภทธุรกิจ
บรรทัดว่างหนึ่งบรรทัดจะปรากฏขึ้น:
- ระหว่างสมาชิกต่อเนื่องของชั้นเรียน ได้แก่ พร็อพเพอร์ตี้ เครื่องมือสร้าง
ฟังก์ชัน คลาสที่ซ้อนกัน ฯลฯ
- ข้อยกเว้น: บรรทัดว่างระหว่าง 2 พร็อพเพอร์ตี้ที่ต่อเนื่องกัน (ไม่มีโค้ดอื่นๆ อยู่ระหว่างพร็อพเพอร์ตี้) จะระบุหรือไม่ก็ได้ บรรทัดว่างดังกล่าวถูกใช้ในการสร้าง การจัดกลุ่มพร็อพเพอร์ตี้และเชื่อมโยงพร็อพเพอร์ตี้เชิงตรรกะ พร้อมพร็อพเพอร์ตี้สนับสนุน หากมี
- ข้อยกเว้น: ระบบจะปกปิดบรรทัดว่างระหว่างค่าคงที่ enum ที่ด้านล่าง
- ระหว่างใบแจ้งยอด ตามต้องการเพื่อจัดระเบียบโค้ด เป็นส่วนย่อยเชิงตรรกะ
- ไม่บังคับก่อนคำสั่งแรกในฟังก์ชัน ก่อนสมาชิกคนแรกของชั้นเรียน หรือหลังจากสมาชิกคนสุดท้าย (ไม่ได้สนับสนุนหรือไม่สนับสนุน)
- ตามที่กำหนดโดยส่วนอื่นๆ ของเอกสารนี้ (เช่น โครงสร้าง)
อนุญาตให้มีบรรทัดว่างติดกันหลายบรรทัด แต่ไม่แนะนำ หรือ เลยแม้แต่น้อย
แนวนอน
นอกเหนือจากที่ภาษาหรือกฎรูปแบบอื่นๆ กำหนดไว้ และนอกเหนือจากตัวอักษร ความคิดเห็น และ KDoc หนึ่ง ASCII ช่องว่างนี้จะปรากฏในตำแหน่งต่อไปนี้เท่านั้น:
- การแยกคำที่สงวนไว้ เช่น
ifforหรือ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()) { }
-
อยู่ในทั้ง 2 ฝั่งของโอเปอเรเตอร์ไบนารี
// 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 แยกบรรทัดกัน ก็ไม่จำเป็นต้องมีบรรทัดว่างระหว่างค่าดังกล่าว ยกเว้นในกรณีที่ค่านั้นกำหนดเป็น Body
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
เมื่อแสดงคำอธิบายประกอบเพียง 1 รายการโดยไม่มีอาร์กิวเมนต์ อาจวางอยู่บนบรรทัดเดียวกับการประกาศก็ได้
@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
ชื่อฟังก์ชัน
ชื่อฟังก์ชันจะเขียนด้วยอูฐและมักจะเป็นคำกริยาหรือวลีกริยา เช่น 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
ตัวปรับแต่ง
ชื่อที่ไม่คงที่
โดยชื่อที่ไม่คงที่จะเขียนด้วย CamlCase ค่าเหล่านี้มีผลกับพร็อพเพอร์ตี้ของอินสแตนซ์ พร็อพเพอร์ตี้ในเครื่อง และชื่อพารามิเตอร์
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() }
พิมพ์ชื่อตัวแปร
ระบบจะตั้งชื่อตัวแปรแต่ละประเภทโดยใช้สไตล์ใดสไตล์หนึ่งจาก 2 สไตล์ ดังนี้
- อักษรตัวพิมพ์ใหญ่ตัวเดียว (ไม่บังคับ) ตามด้วย
ตัวเลขเดี่ยว (เช่น
E,T,X,T2) - ชื่อในรูปแบบที่ใช้สำหรับชั้นเรียน แล้วตามด้วยตัวพิมพ์ใหญ่
ตัวอักษร
T(เช่นRequestT,FooBarT)
เคส Camel
บางครั้งอาจมีวิธีที่สมเหตุสมผลมากกว่า 1 วิธีในการแปลงวลีภาษาอังกฤษให้เป็นตัวอักษรพิมพ์ใหญ่ เช่น เมื่อมีตัวย่อหรือโครงสร้างที่ผิดปกติอย่าง “IPv6” หรือ “iOS” หากต้องการปรับปรุงการคาดการณ์ ให้ใช้รูปแบบต่อไปนี้
ขึ้นต้นด้วยรูปแบบร้อยแก้วของชื่อ:
- แปลงวลีเป็น ASCII แบบธรรมดาและลบเครื่องหมายอะพอสทรอฟีออก เช่น "อัลกอริทึมของ Müller" อาจกลายเป็น "อัลกอริทึมของ Mullers"
- ให้หารผลลัพธ์นี้เป็นคำ โดยเว้นวรรคและใช้เครื่องหมายวรรคตอนที่เหลือ (โดยทั่วไปคือขีดกลาง) แนะนำ: หากคำใดมีลักษณะคล้ายตัวอูฐทั่วไปอยู่แล้วตามการใช้งานทั่วไป ให้แยกคำนี้ออกเป็นส่วนๆ (เช่น “AdWords” กลายเป็น “คำโฆษณา”) โปรดทราบว่าคำเช่น “iOS” นั้นไม่ใช่คำที่ใช้ตัวพิมพ์เล็ก/ใหญ่แบบอูฐ ขัดต่อกฎเกณฑ์ใดๆ ดังนั้นคำแนะนำนี้จึงไม่มีผลบังคับใช้
- จากนั้นพิมพ์ตัวพิมพ์เล็กทุกอย่าง (รวมถึงตัวย่อ) จากนั้นดำเนินการอย่างใดอย่างหนึ่งต่อไปนี้
- ทำให้อักขระตัวแรกของแต่ละคำเป็นตัวพิมพ์ใหญ่เป็นตัวพิมพ์ใหญ่
- ทำให้อักขระตัวแรกของแต่ละคำเป็นตัวพิมพ์ใหญ่ ยกเว้นอักษรตัวแรกเป็นตัวพิมพ์ใหญ่ แบบอูฐ
- สุดท้าย รวมทุกคำไว้ในตัวระบุเดียว
โปรดทราบว่าไม่คำนึงถึงตัวพิมพ์เล็กหรือใหญ่ของคำต้นฉบับเกือบทั้งหมด
| แบบฟอร์มร้อยแก้ว | ถูกต้อง | ไม่ถูกต้อง |
|---|---|---|
| "คำขอ HTTP สำหรับ XML" | 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
ย่อหน้า
บรรทัดว่าง 1 บรรทัด ซึ่งก็คือบรรทัดที่มีเฉพาะเครื่องหมายดอกจันนำหน้าที่ปรับแนวไว้เท่านั้น
(*) แสดงระหว่างย่อหน้าและก่อนกลุ่มแท็กบล็อก หากมี
บล็อกแท็ก
"แท็กบล็อก" มาตรฐานที่ใช้จะปรากฏในลำดับ
@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. */) ในกรณีที่ผู้อ่านทั่วไปอาจไม่มี
ลองคิดดูว่าคำว่า "ชื่อ Canonical" คืออะไร หมายความว่า
ข้อยกเว้น: ลบล้าง
ในบางครั้ง KDoc จะไม่ปรากฏขึ้นในเมธอดที่ลบล้างเมธอดประเภทขั้นสูง