跳转到内容

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)

参考资料

[编辑]