跳转到内容

Kotlin/程式撰寫慣例

维基教科书,自由的教学读本

程式撰寫慣例

[编辑]

套用規範建議

[编辑]

To configure the IntelliJ formatter according to this style guide, please install Kotlin plugin version 1.2.20 or newer, go to Settings | Editor | Code Style | Kotlin, click Set from… link in the upper right corner, and select Predefined style | Kotlin style guide from the menu.

To verify that your code is formatted according to the style guide, go to the inspection settings and enable the Kotlin | Style issues | File is not formatted according to project settings inspection. Additional inspections that verify other issues described in the style guide (such as naming conventions) are enabled by default.

程式碼架構

[编辑]

命名規則

[编辑]

函式名稱

[编辑]

函式名稱,參數以及本地變數的命名,都是小寫開頭的駝峰格式,不包含底線:

fun processDeclarations() { /*...*/ }
var declarationCount = 1

例外情況:建立某介面的物件所使用的工廠方法,可以直接用該介面命名,因此是大寫開頭:

interface Foo { /*...*/ }

class FooImpl : Foo { /*...*/ }

fun Foo(): Foo { return FooImpl() }

測試函式名稱

[编辑]

如果是在測試程式碼裡面(也僅有在測試程式程式碼內允許),可以使用重音符「`」括弧起來,內含空白的一段文字作為函式名稱。這類函式目前在 Android 實際環境運作是不支援的。

測試程式碼內,也允許在函式命名裡面使用底線。

class MyTestCase {
     @Test fun `ensure everything works`() { /*...*/ }
     
     @Test fun ensureEverythingWorks_onAndroid() { /*...*/ }
}

屬性名稱

[编辑]

常量名稱(標有 const 的屬性,或者保存不可變數據的沒有自定義 get 函數的頂層/對象 val 屬性)應該使用大寫、以底線分隔的風格命名:

const val MAX_COUNT = 8
val USER_NAME_FIELD = "UserName"

帶有行為的物件,或者可變數據的頂層/對象屬性的名稱,應該使用小駝峰風格命名:

val mutableCollection: MutableSet<String> = HashSet()

保存單例對象引用的屬性的名稱,可以使用與 object 定義相同的風格命名:

val PersonComparator: Comparator<Person> = /*...*/

對於枚舉常數的命名,可以使用大寫以底線分隔的名稱 (enum class Color { RED, GREEN })也可使用大駝峰命名,具體命名風格取決於用途。

為備存用屬性命名

[编辑]

如果一個類別有兩個概念相同的屬性,一個是對外的部分,另一個是內部實作細節,那麽使用下劃線作為私有屬性名稱的前綴:

class C {
    private val _elementList = mutableListOf<Element>()

    val elementList: List<Element>
         get() = _elementList
}

選好的名字

[编辑]

類別的名字通常會是某個名詞或名詞片語,解釋這個類別在做什麼,比方說:ListPersonReader

函式的名稱通常是動詞或者動詞片語,解釋這個函式的行為,比方說:closereadPersons

函式名稱應該要看得出來其行為是改變輸入的參數,還是回傳一個新的物件。比方說:sort 通常是將輸入的集合進行排序,不會回傳新的集合;sorted 則是回傳一個以排序好的集合,不會更動輸入的集合。

命名要能夠看得出用意,所以命名內盡量避免意義不清晰的單字(比方說 Manager,Wrapper 之類)

如果在宣告名稱中使用縮寫,該縮寫只有兩個字母(比方說 I/O)的話,兩個字母都要大寫(IOStream)。如果該縮寫多於兩個字母,那麼只有第一個字母要大寫(XmlFormatter,HttpInputStream)

格式

[编辑]

用四個空白縮排,不要用 Tab

左大括號前面加上一個空白,並且放在結構一開始這行的最尾端。

右大括號則是獨立一行,並對其結構宣告的開頭。

if (elements != null) {
    for (element in elements) {
        // ...
    }
}

(註記:Kotlin 裡,分號是非必須的,所以換行非常重要。編譯器會假設你是用以上風格的括號方式,如果使用不同風格,可能會導致意外的編譯結果)

橫向空白

[编辑]

除了「範圍」運算子不需要之外(0..1),二元運算子前後各需要一個空白(比方說: a + b)。

一元運算子前後不可加上空白(比方說:a++)

控制流關鍵字(if、when、for 和 while)和對應的小括號之間要加上一個空白

Do not put a space before an opening parenthesis in a primary constructor declaration, method declaration or method call.

class A(val x: Int)

fun foo(x: Int) { ... }

fun bar() {
    foo(1)
}


Never put a space after (, [, or before ], ).

Never put a space around . or ?.: foo.bar().filter { it > 2 }.joinToString(), foo?.bar()

單行註解的 // 後面要加上一個空白,比方說:// 這是單行註解

Do not put spaces around angle brackets used to specify type parameters: class Map<K, V> { ... }

Do not put spaces around ::: Foo::class, String::length

Do not put a space before ? used to mark a nullable type: String?

As a general rule, avoid horizontal alignment of any kind. Renaming an identifier to a name with a different length should not affect the formatting of either the declaration or any of the usages.

冒號

[编辑]

類別宣告格式

[编辑]

修飾宣告

[编辑]

標註格式

[编辑]

檔案標註

[编辑]

函式格式

[编辑]

Expression body formatting

[编辑]

Property formatting

[编辑]

Formatting control flow statements

[编辑]

Method call formatting

[编辑]

Chained call wrapping

[编辑]

Lambda 格式

[编辑]

文件註解

[编辑]

避免多餘結構

[编辑]

Unit

[编辑]

如果函式回傳 Unit 那麼可以省略

fun foo() { // ": Unit" 被省略了

}

分號

[编辑]

盡量避免分號

字串樣板

[编辑]

如果樣板內只有單純變數名稱,避免用大括號包起來。只有在樣板包含比較長的表達式時才需要用大括號處理

println("$name has ${children.size} children")

慣用語言功能

[编辑]

Immutability

[编辑]

Default parameter values

[编辑]

Type aliases

[编辑]

Lambda parameters

[编辑]

Returns in a lambda

[编辑]

Named arguments

[编辑]

Using conditional statements

[编辑]

if versus when

[编辑]

Using nullable Boolean values in conditions

[编辑]

Using loops

[编辑]

Loops on ranges

[编辑]

Using strings

[编辑]

Functions vs Properties

[编辑]

Using extension functions

[编辑]

Using infix functions

[编辑]

Factory functions

[编辑]

Platform types

[编辑]

Using scope functions

[编辑]

library 的撰寫慣例

[编辑]

When writing libraries, it's recommended to follow an additional set of rules to ensure API stability:

  • Always explicitly specify member visibility (to avoid accidentally exposing declarations as public API)
  • Always explicitly specify function return types and property types (to avoid accidentally changing the return type when the implementation changes)
  • Provide KDoc comments for all public members, with the exception of overrides that do not require any new documentation (to support generating documentation for the library)

參考資料

[编辑]