該規(guī)范參考Kotlin語言中文站進(jìn)行定義
應(yīng)用codeStyle
一嗽上、源代碼組織結(jié)構(gòu)
1壳繁、目錄結(jié)構(gòu)
Kotlin和Java相似绞幌,都有包的概念。每一個(gè)Kotlin文件都能以一條package語句開頭蚕脏,那么這個(gè)文件中的所有類、函數(shù)及屬性都會(huì)被放到這個(gè)包中,屬于這個(gè)包糟把。
如果其它文件中也是以同樣的package語句開頭亩钟,那么它們屬于同一個(gè)包乓梨,不管文件放在哪個(gè)目錄結(jié)構(gòu)下,不用和Java一樣清酥,必須把類文件放在和包結(jié)構(gòu)相匹配的目錄結(jié)構(gòu)下扶镀。同一個(gè)包下的內(nèi)容可以互相使用。
Kotlin推薦的目錄結(jié)構(gòu)遵循省略了公共根包的包結(jié)構(gòu),即每個(gè)文件應(yīng)存儲(chǔ)在與其 package 語句對(duì)應(yīng)的目錄中焰轻。
一句話概況:每個(gè)文件應(yīng)存儲(chǔ)在與其 package 語句對(duì)應(yīng)的目錄中狈惫!
2、源文件名稱
如果 Kotlin 文件包含單個(gè)類(以及可能相關(guān)的頂層聲明),那么文件名應(yīng)該與該類的名稱相同胧谈,并追加 .kt 擴(kuò)展名忆肾。如果文件包含多個(gè)類或只包含頂層聲明, 那么選擇一個(gè)描述該文件所包含內(nèi)容的名稱菱肖,并以此命名該文件客冈。 使用首字母大寫的駝峰風(fēng)格, 例如 ProcessDeclarations.kt
稳强。
一句話概況:文件名采用駝峰命名
3场仲、類布局
通常,一個(gè)類的內(nèi)容按以下順序排列:
屬性聲明與初始化塊
次構(gòu)造函數(shù)
方法聲明
伴生對(duì)象
不要按字母順序或者可見性對(duì)方法聲明排序退疫,也不要將常規(guī)方法與擴(kuò)展方法分開渠缕。而是要把相關(guān)的東西放在一起,這樣從上到下閱讀類的人就能夠跟進(jìn)所發(fā)生事情的邏輯褒繁。
將嵌套類放在緊挨使用這些類的代碼之后亦鳞。如果打算在外部使用嵌套類,而且類中并沒有引用這些類棒坏,那么把它們放到末尾燕差,在伴生對(duì)象之后。
二坝冕、命名規(guī)則
在 Kotlin 中徒探,包名與類名的命名規(guī)則非常簡(jiǎn)單:
包的名稱總是小寫且不使用下劃線(org.example.project)。 通常不鼓勵(lì)使用多個(gè)詞的名稱喂窟,但是如果確實(shí)需要使用多個(gè)詞测暗,可以將它們連接在一起或使用駝峰風(fēng)格(org.example.myProject)。
類與對(duì)象的名稱以大寫字母開頭并使用駝峰風(fēng)格:
open class DeclarationProcessor { /*……*/ }
object EmptyDeclarationProcessor : DeclarationProcessor() { /*……*/ }
函數(shù)名
函數(shù)磨澡、屬性與局部變量的名稱以小寫字母開頭偷溺、使用駝峰風(fēng)格而不使用下劃線:
fun processDeclarations() { /*……*/ }
var declarationCount = 1
例外:用于創(chuàng)建類實(shí)例的工廠函數(shù)可以與抽象返回類型具有相同的名稱:
interface Foo { /*……*/ }
class FooImpl : Foo { /*……*/ }
fun Foo(): Foo { return FooImpl() }
屬性名
常量名稱(標(biāo)有 const
的屬性,或者保存不可變數(shù)據(jù)的沒有自定義 get
函數(shù)的頂層/對(duì)象 val
屬性)應(yīng)該使用大寫钱贯、下劃線分隔的名稱:
const val MAX_COUNT = 8
val USER_NAME_FIELD = "UserName"
保存帶有行為的對(duì)象或者可變數(shù)據(jù)的頂層/對(duì)象屬性的名稱應(yīng)該使用駝峰風(fēng)格名稱:
val mutableCollection: MutableSet<String> = HashSet()
保存單例對(duì)象引用的屬性的名稱可以使用與 object 聲明相同的命名風(fēng)格:
val PersonComparator: Comparator<Person> = /*...*/
對(duì)于枚舉常量挫掏,可以使用大寫、下劃線分隔的名稱(enum class Color { RED, GREEN }
)也可使用首字母大寫的常規(guī)駝峰名稱秩命,具體取決于用途尉共。
幕后屬性的名稱
如果一個(gè)類有兩個(gè)概念上相同的屬性,一個(gè)是公共 API 的一部分弃锐,另一個(gè)是實(shí)現(xiàn)細(xì)節(jié)袄友,那么使用下劃線作為私有屬性名稱的前綴(這種方式借鑒了Flutter私有屬性的命名方式):
class C {
private val _elementList = mutableListOf<Element>()
val elementList: List<Element>
get() = _elementList
}
命名有良好習(xí)慣
類的名稱通常是用來解釋類是什么的名詞或者名詞短語:xxxListAdapter、 PersonReader霹菊。
方法的名稱通常是動(dòng)詞或動(dòng)詞短語剧蚣,說明該方法做什么:close支竹、 readPersons。 修改對(duì)象或者返回一個(gè)新對(duì)象的名稱也應(yīng)遵循建議鸠按。例如 sort 是對(duì)一個(gè)集合就地排序礼搁,而 sorted 是返回一個(gè)排序后的集合副本。
名稱應(yīng)該表明實(shí)體的目的是什么目尖,所以最好避免在名稱中使用無意義的單詞 馒吴。
當(dāng)使用首字母縮寫作為名稱的一部分時(shí),如果縮寫由兩個(gè)字母組成瑟曲,就將其大寫(IOStream)饮戳; 而如果縮寫更長(zhǎng)一些,就只大寫其首字母(XmlFormatter洞拨、 HttpInputStream)扯罐。
格式化
使用 4 個(gè)空格縮進(jìn)。不要使用 tab烦衣。(可在AS中設(shè)置好code style,一個(gè)tab等于4個(gè)空格進(jìn)行縮進(jìn))
對(duì)于花括號(hào)歹河,將左花括號(hào)放在結(jié)構(gòu)起始處的行尾,而將右花括號(hào)放在與左括結(jié)構(gòu)橫向?qū)R的單獨(dú)一行琉挖。
if (elements != null) {
for (element in elements) {
// ……
}
}
在 Kotlin 中,分號(hào)是可選的涣脚,因此換行很重要示辈。語言設(shè)計(jì)采用 Java 風(fēng)格的花括號(hào)格式,如果嘗試使用不同的格式化風(fēng)格遣蚀,那么可能會(huì)遇到意外的行為矾麻。
橫向空白
在二元操作符左右留空格(a + b)。例外:不要在“range to”操作符(0..i)左右留空格芭梯。
不要在一元運(yùn)算符左右留空格(a++)
在控制流關(guān)鍵字(if险耀、 when、 for 以及 while)與相應(yīng)的左括號(hào)之間留空格玖喘。
(這里容易被忽略甩牺,小組討論是否需要。建議使用)
不要在主構(gòu)造函數(shù)聲明累奈、方法聲明或者方法調(diào)用的左括號(hào)之前留空格贬派。
class A(val x: Int)
fun foo(x: Int) { …… }
fun bar() {
foo(1)
}
絕不在 (、 [ 之后或者 ]澎媒、 ) 之前留空格搞乏。
絕不在. 或者 ?. 左右留空格:foo.bar().filter { it > 2 }.joinToString(), foo?.bar()
在 // 之后留一個(gè)空格:
// 這是一條注釋
不要在用于指定類型參數(shù)的尖括號(hào)前后留空格:class Map<K, V> { …… }
不要在 :: 前后留空格:Foo::class、 String::length
不要在用于標(biāo)記可空類型的 ? 前留空格:String?
冒號(hào)
在以下場(chǎng)景中的冒號(hào)":"之前留一個(gè)空格:
當(dāng)它用于分隔類型與超類型時(shí)戒努;
當(dāng)委托給一個(gè)超類的構(gòu)造函數(shù)或者同一類的另一個(gè)構(gòu)造函數(shù)時(shí)请敦;
在 object 關(guān)鍵字之后。
而當(dāng)分隔聲明與其類型時(shí),不要在 : 之前留空格侍筛。(指聲明屬性時(shí)或者函數(shù)定義返回類型時(shí))
在 : 之后總要留一個(gè)空格萤皂。
abstract class Foo<out T : Any> : IFoo {
abstract fun foo(a: Int): T
}
class FooImpl : Foo() {
constructor(x: String) : this(x) { /*……*/ }
val x = object : IFoo { /*……*/ }
}
類頭格式化
有少數(shù)幾個(gè)參數(shù)的類可以寫成一行:
class Person(id: Int, name: String)
具有較長(zhǎng)類頭的類應(yīng)該格式化,以使每個(gè)主構(gòu)造函數(shù)參數(shù)位于帶有縮進(jìn)的單獨(dú)一行中勾笆。 此外敌蚜,右括號(hào)應(yīng)該另起一行。如果我們使用繼承窝爪,那么超類構(gòu)造函數(shù)調(diào)用或者實(shí)現(xiàn)接口列表應(yīng)位于與括號(hào)相同的行上:
class Person(
id: Int,
name: String,
surname: String
) : Human(id, name) {
// ……
}
對(duì)于多個(gè)接口弛车,應(yīng)首先放置超類構(gòu)造函數(shù)調(diào)用,然后每個(gè)接口應(yīng)位于不同的行中:
class Person(
id: Int,
name: String,
surname: String
) : Human(id, name),
KotlinMaker {
// ……
}
對(duì)于具有很長(zhǎng)超類型列表的類蒲每,在冒號(hào)后面換行纷跛,并橫向?qū)R所有超類型名:
class MyFavouriteVeryLongClassHolder :
MyLongHolder<MyFavouriteVeryLongClass>(),
SomeOtherInterface,
AndAnotherOne {
fun foo() { /*...*/ }
}
為了將類頭與類體分隔清楚,當(dāng)類頭很長(zhǎng)時(shí)邀杏,可以在類頭后放一空行 (如上例所示)或者將左花括號(hào)放在獨(dú)立行上:
class MyFavouriteVeryLongClassHolder :
MyLongHolder<MyFavouriteVeryLongClass>(),
SomeOtherInterface,
AndAnotherOne
{
fun foo() { /*...*/ }
}
個(gè)人較傾向于第一種:花括號(hào)放在超類后
構(gòu)造函數(shù)參數(shù)使用常規(guī)縮進(jìn)(4 個(gè)空格)贫奠。
理由:這確保了在主構(gòu)造函數(shù)中聲明的屬性與 在類體中聲明的屬性具有相同的縮進(jìn)。
Unit
如果函數(shù)返回 Unit 類型望蜡,該返回類型應(yīng)該省略:
fun foo() { // 省略了 ": Unit"
}
Lambda表達(dá)式
在lambda表達(dá)式中, 大括號(hào)左右要加空格唤崭,分隔參數(shù)與代碼體的箭頭左右也要加空格 。lambda表達(dá)應(yīng)盡可能不要寫在圓括號(hào)中
list.filter { it > 10 }.map { element -> element * 2 }
在非嵌套的短lambda表達(dá)式中脖律,最好使用約定俗成的默認(rèn)參數(shù) it 來替代顯式聲明參數(shù)名 谢肾。在嵌套的有參數(shù)的lambda表達(dá)式中,參數(shù)應(yīng)該總是顯式聲明小泉。
在多行的 lambda 表達(dá)式中聲明參數(shù)名時(shí)芦疏,將參數(shù)名放在第一行,后跟箭頭與換行符:
appendCommaSeparated(properties) { prop ->
val propertyValue = prop.get(obj) // ……
}
如果參數(shù)列表太長(zhǎng)而無法放在一行上微姊,請(qǐng)將箭頭放在單獨(dú)一行:
foo {
context: Context,
environment: Env
->
context.configureEnv(environment)
}