Coding Style

Kotlin Coding Style

命名

駝峰式大小寫

命名步驟如下:

  1. 將所有內容(包括首字母縮寫)小寫、將ISO、XML、IP這些常見大寫字母也變小寫。
  2. 將每個單字的第一個字元大寫,以產生Pascal 大小寫。
  3. 將除第一個單字之外的每個單字的第一個字元大寫。
未大小寫前 正確 錯誤
XML Http Request XmlHttpRequest XMLHTTPRequest
new customer ID newCustomerId newCustomerID
inner stopwatch innerStopwatch innerStopWatch
supports IPv6 on iOS supportsIpv6OnIos supportsIPv6OnIOS
YouTube importer YouTubeImporter YoutubeImporter

此處命名方式跟C++、Java不同,C++與Java是ISO、XML、IP不用轉小寫。

變數

採用camelCase 大小寫形式寫成。物件屬性、參數、可變集合。

1
2
3
val variable = "var"
val nonConstScalar = "non-const"
val mutableCollection: MutableSet

常數

常數大寫,單字用底線分隔。

什麼是常數呢?
常數是沒有自訂get函式的val屬性,其內容絕對不可變,不可變類型和不可變集合,以及const都為常數。

1
2
3
4
5
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

函式

函式名稱以camelCase 大小寫形式編寫,通常是動詞或動詞片語。例如,sendMessage或stop。

1
2
3
fun sendMessage(name: String) {
    // …
}

測試函式:允許在測試函式名稱中出現底線,用於分隔名稱的邏輯組成部分。

1
2
3
@Test fun pop_emptyStack() {
    // …
}

類別與介面

類別名稱採用PascalCase 大小寫形式編寫,第一個字母大寫,通常是名詞。例如,Character或ImmutableList。介面名稱也可以是名詞或名詞片語(例如List),但有時也可以是形容詞或形容詞片語(例如Readable)。

1
class MyClass { }
1
class Bar { }

測試類別

測試類別的命名方式是以測試的類別的名稱開頭且以Test結尾。例如,HashTest或HashIntegrationTest。

1
class HashTest { }

有註解的函式

JetPackCompose中帶有@Composable註解且返回Unit的函式,函式名字首大寫,採用大小寫形式並以名詞形式命名。

1
2
3
4
@Composable
fun NameTag(name: String) {
    // …
}

縮排

縮排四個空格。

程式語言 縮排
C++ 2格
Java 2格
Kotlin 4格

換行

類別換行

類別的連續成員(屬性、建構子、函式、巢狀類別等)之間

邏輯分組、將程式碼分割為一些邏輯子部分,可換行。

函式與函式之間有換行

1
2
3
4
5
6
7
fun sum3(vararg num:Int){
    // ...
}

fun sum4(vararg num:Int){
    // ...
}

函式參數換行

當函式簽章不適合放在一行上時,應讓每個參數宣告獨佔一行。以此格式定義的參數應使用單縮排(+4)。右圓括號( )) 和傳回型別獨佔一行,沒有額外的縮排。

1
2
3
4
5
6
7
fun <T> Iterable<T>.joinToString(
    separator: CharSequence = ", ",
    prefix: CharSequence = "",
    postfix: CharSequence = ""
): String {
    // …
}

變數換行

當屬性初始化式不適合放在一行時,應在等號( =) 後面換行,並進行縮排。

1
2
private val defaultCharset: Charset? =
    EncodingRegistry.getInstance().getDefaultCharsetForPropertiesFiles(file)

get set換行

宣告get和/或set函式的屬性應讓每個函式獨佔一行,並使用正常的縮排(+4)。對它們進行格式設定時,使用的規則與函式相同。

1
2
3
4
var directory: File? = null
    set(value) {
        // …
    }

只讀屬性可以使用適合放在一行的較短語法。

1
val defaultExtension: String get() = "kt"

if、for、when、do、while空格

if後面有空格,左大括號{前面有空格,else前後與大括號之間都有空格。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// WRONG!
if (list.isEmpty()){
}

// Okay
if (list.isEmpty()) {
}

// WRONG!
}else {
}

// Okay
} else {
}

// WRONG!
for(i in 0..1) {
}

// Okay
for (i in 0..1) {
}

運算式空格

1
2
3
4
5
// WRONG!
val two = 1+1

// Okay
val two = 1 + 1

Lambda空格

箭頭 -> 前後都有空格

1
2
3
4
5
// WRONG!
ints.map { value->value.toString() }

// Okay
ints.map { value -> value.toString() }

變數、參數類型冒號

注意變數後面沒有空格,冒號後面一個空格,再來是類型。

1
val str: String = "Hello"

函式參數,注意d變數後面沒有空格,冒號後面一個空格,再來是類型。

1
2
3
fun printDouble(d: Double) {
    println(d)
}

繼承、介面、泛型冒號

繼承冒號(:)前後要空格

1
2
3
4
5
// WRONG!
class Foo: Runnable

// Okay
class Foo : Runnable

泛型T的繼承,繼承冒號(:)前後要空格

注意T : Comparable

1
2
3
4
5
6
// WRONG
fun <T: Comparable> max(a: T, b: T)

// Okay
// 注意T : Comparable
fun <T : Comparable> max(a: T, b: T)
1
2
// WRONG
fun <T> max(a: T, b: T) where T: Comparable<T>
1
2
3
// Okay
// 注意T : Comparable
fun <T> max(a: T, b: T) where T : Comparable<T>

逗號後面空格

逗號後面要一個空白,前面不用空白

1
2
3
4
5
// WRONG!
val oneAndTwo = listOf(1,2)

// Okay
val oneAndTwo = listOf(1, 2)

不用空格

::前後沒有空格

1
2
3
4
5
// WRONG!
val toString = Any :: toString

// Okay
val toString = Any::toString

範圍運算子(..)

1
2
3
4
5
6
7
8
9
// WRONG
for (i in 1 .. 4) {
  print(i)
}

// Okay
for (i in 1..4) {
  print(i)
}

if、for、when、do、while大括號

if、for、when分支、do和while語句及表達式都需要大括號,即使主體為空或僅包含一個語句也是如此。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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)
}

大括號{}換行

1
2
3
4
5
6
7
8
try {
    doSomething()
} catch (e: Exception) {} // WRONG!

try {
    doSomething()
} catch (e: Exception) {
} // Okay

列舉的大括號,可以不用換行。

1
enum class Answer { YES, NO, MAYBE }

省略{}大括號

if/else條件語句只有一行才能省略大括號。

1
val value = if (string.isEmpty()) 0 else 1  // Okay

超過一行,還是要有大括號。

錯誤範例

1
2
3
4
val value = if (string.isEmpty())  // WRONG!
    0
else
    1

對的範例

1
2
3
4
5
val value = if (string.isEmpty()) { // Okay
    0
} else {
    1
}

省略類型

變數、函式傳回值有初始值可以推斷類型,就可以省略類型。

省略變數類型

1
2
3
val str: String = "Hello"
// becomes
val str = "Hello"

省略函式傳回類型

1
2
3
override fun toString(): String = "Hey"
// becomes
override fun toString() = "Hey"

省略變數類型

1
2
3
private val ICON: Icon = IconLoader.getIcon("/icons/kotlin.png")
// becomes
private val ICON = IconLoader.getIcon("/icons/kotlin.png")

列舉

將枚舉中的常數放在單獨的行上時,它們之間不需要空白行,但它們有主體body(大括號{}包起來的部分)時,需要空白行隔開。

1
2
3
4
5
6
7
8
9
enum class Answer {
    YES,
    NO,

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

results matching ""

    No results matching ""