1、源文件命名
- 所有源文件都必须编码为 UTF-8。
- 如果源文件只包含一个顶级类,则文件名应为该类的名称(区分大小写)加上 .kt 扩展名。
- 如果源文件包含多个顶级声明,则应选择一个可描述文件内容的名称(采用 PascalCase 大小写形式;如果文件名为复数,亦可采用驼峰命名法)并加上 .kt 扩展名。
cpp
// 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() = // ...
2、特殊字符
(1) 空白字符
除了行终止符序列之外,ASCII 水平空格字符 (0x20) 是唯一一种可以出现在源文件中任意位置的空白字符。这意味着:
- 字符串和字符字面量中的其他所有空白字符都会进行转义。
- 制表符不用于缩进。
(2) 特殊转义序列
对于任何具有特殊转义序列(\b、\n、\r、\t、'、"、\ 和 $)的字符,将使用该序列,而不是相应的 Unicode 转义字符(例如 \u000a)。
(3)非 ASCII 字符
对于其余非 ASCII 字符,要么使用实际的 Unicode 字符(例如 ∞),要么使用等效的 Unicode 转义字符(例如 \u221e)。具体选择仅取决于哪种字符可使代码更容易阅读和理解。建议不要对任何位置的可输出字符使用 Unicode 转义字符,强烈建议不要在字符串字面量和注释之外使用 Unicode 转义字符。
cpp
// 最好:即使没有注释,也非常清楚。
val unitAbbrev = "μs"
// 差:没有理由对可打印字符使用转义。
val unitAbbrev = "\u03bcs" // μs
// 差:读者不知道这是什么。
val unitAbbrev = "\u03bcs"
// 好:对不可打印字符使用转义,并在必要时添加注释。
return "\ufeff" + content
3、结构
- .kt 文件由下面几部分组成(按顺序列出 ),各部分用一个空白行 隔开:
- 版权和/或许可标头(可选)
- 文件级注解
- package 语句
- import 语句
- 顶级声明
(1)版权/许可
- 如果版权或许可标头需要放在文件中,应将其放在多行注释的上方,并让其紧挨着多行注释。
cpp
/*
* Copyright 2017 Google, Inc.
*
* ...
*/
- 请勿使用 KDoc 样式或单行样式的注释。
cpp
KDoc 样式
/**
* Copyright 2017 Google, Inc.
*
* ...
*/
单行样式
// Copyright 2017 Google, Inc.
//
// ...
(2)文件级注解
- 应将具有 "file" 使用处目标的注解 放在任何标头注释和软件包声明之间。
cpp
@file:JvmName("Foo")
package org.jetbrains.demo
(3)package 语句
- package 语句不受任何列限制且从不换行。
(4)import 语句
- 应将类、函数和属性的 import 语句归在单个列表中并按 ASCII 进行排序。
- 不允许(任何类型的)通配符导入。
- 与 package 语句类似,import 语句也不受列限制且从不换行。
(5)顶级声明
- .kt 文件可以在顶级声明一个或多个类型、函数、属性或类型别名。
- 对文件的内容量和内容顺序 没有做出明确的限制。通常按从上到下的顺序读取 源文件,顺序通常应反映出位置比较靠上的声明将有助于理解位置比较靠下的声明。
- 每个类都采用某种逻辑顺序,类的维护人员在被问及时应可以解释清楚相应逻辑顺序。例如,新函数不应直接习惯性地添加到类的末尾,因为这样会产生"按添加日期先后顺序"排序,而这不是逻辑排序。
4、格式设置
(1)大括号
- when 分支以及具有不超过一个 else 分支且仅占一行的 if 表达式不需要大括号。
cpp
if (string.isEmpty()) return
val result =
if (string.isEmpty()) DEFAULT_VALUE else string
when (value) {
0 -> return
// ...
}
- 任何 if、for、when 分支、do 和 while 语句及表达式都需要大括号,即使主体为空或仅包含一个语句也是如此。
cpp
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)
}
- 非空块 :对于非空块和类似块的构造,大括号遵循 Kernighan 和 Ritchie (K&R) 样式("埃及括号"):
- 左大括号前面没有换行符。
- 左大括号后面有换行符。
- 右大括号前面有换行符。
- 仅当右大括号终止语句或者终止函数、构造函数或命名类的主体时,它后面才有换行符。例如,如果大括号后跟 else 或一个英文逗号,就不应在它后面换行。
cpp
object : MyClass() {
override fun foo() {
if (condition()) {
try {
something()
} catch (e: ProblemException) {
recover()
}
} else if (otherCondition()) {
somethingElse()
} else {
lastThing()
}
}
}
- 空块:空块或类似块的构造必须采用 K&R 样式。
cpp
try {
doSomething()
} catch (e: Exception) {} // WRONG!
try {
doSomething()
} catch (e: Exception) {
} // Okay
- 表达式:仅当整个表达式适合放在一行时,用作表达式的 if/else 条件语句才能省略大括号。
cpp
// Okay
val value = if (string.isEmpty()) 0 else 1
// WRONG!
val value = if (string.isEmpty())
0
else
1
// Okay
val value = if (string.isEmpty()) {
0
} else {
1
}