Kotlin官方文档-基础知识-编码规范(翻译官方文档)

90 阅读21分钟

Kotlin 全量关键字全面整理,并附上简洁示例,确保每一个关键字都清楚易懂。

Kotlin官方文档-基础知识-基础语法(翻译官方文档+自我总结)

Kotlin官方文档-基础知识-常用惯用语法(翻译官方文档+自我总结)

Kotlin官方文档-基础知识-编码规范(翻译官方文档)

2025年8月26日

一套广为人知且易于遵循的编码规范对任何编程语言而言都至关重要。本文档为使用 Kotlin 开发的项目提供了代码风格与代码组织方面的指导准则。

(注:文档翻译部分由 AI 完成)

1. 在 IDE 中配置代码风格

Kotlin 最常用的两款 IDE——IntelliJ IDEAAndroid Studio——均提供了强大的代码风格支持。你可以对其进行配置,使其按照指定的代码风格自动格式化代码。

1.1 应用风格指南

  1. 进入 设置/偏好设置 | 编辑器 | 代码风格 | Kotlin
  2. 点击 从...导入设置(Set from...)。
  3. 选择 Kotlin 风格指南(Kotlin style guide)。

1.2 验证代码是否符合风格指南

  1. 进入 设置/偏好设置 | 编辑器 | 检查 | 常规(Settings/Preferences | Editor | Inspections | General)。
  2. 启用 格式不正确(Incorrect formatting)检查。用于验证风格指南中描述的其他问题(如命名规范)的附加检查默认已启用。

2. 源代码组织

2.1 目录结构

在纯 Kotlin 项目中,推荐的目录结构遵循包结构,但省略公共根包。例如,如果项目中的所有代码都位于 org.example.kotlin 包及其子包中,那么属于 org.example.kotlin 包的文件应直接放在源码根目录下,而属于 org.example.kotlin.network.socket 包的文件则应放在源码根目录的 network/socket 子目录中。

JVM 平台说明:在 Kotlin 与 Java 混合使用的项目中,Kotlin 源文件应与 Java 源文件位于同一源码根目录下,并遵循相同的目录结构:每个文件都应存储在与其包声明对应的目录中。

2.2 源文件命名

如果一个 Kotlin 文件仅包含一个类或接口(可能包含相关的顶层声明),则该文件的名称应与类名相同,并添加 .kt 扩展名。此规则适用于所有类型的类和接口。如果一个文件包含多个类,或仅包含顶层声明,则应选择一个能描述文件内容的名称作为文件名。文件名采用大驼峰命名法,即每个单词的首字母大写。例如:ProcessDeclarations.kt

文件名应能清晰反映文件中代码的功能。因此,应避免在文件名中使用无意义的词汇,如 Util

2.3 多平台项目

在多平台项目中,平台特定源码集中包含顶层声明的文件,其名称应添加与源码集名称对应的后缀。例如:

  • jvmMain/kotlin/Platform.jvm.kt
  • androidMain/kotlin/Platform.android.kt
  • iosMain/kotlin/Platform.ios.kt

对于公共源码集(common source set),包含顶层声明的文件不应添加后缀。例如:commonMain/kotlin/Platform.kt

2.4 源文件内部组织

只要多个声明(类、顶层函数或属性)在语义上紧密相关,且文件大小保持合理(不超过几百行),就建议将它们放在同一个 Kotlin 源文件中。

特别是,为某个类定义所有客户端都需要使用的扩展函数时,应将这些扩展函数与该类本身放在同一个文件中。如果扩展函数仅对特定客户端有意义,则应将其放在该客户端代码附近。避免创建仅用于存放某个类的所有扩展函数的文件。

2.5 类结构

类的内容应按以下顺序排列:

  1. 属性声明和初始化块
  2. 次构造函数
  3. 方法声明
  4. 伴生对象

不要按字母顺序或可见性对方法声明进行排序,也不要将常规方法与扩展方法分开。相反,应将相关内容放在一起,以便阅读类的人从上到下能够理解逻辑。选择一种顺序(要么先放高层级内容,要么反之)并保持一致。

嵌套类应放在使用它们的代码附近。如果嵌套类旨在供外部使用,且不在类内部被引用,则应将其放在末尾,位于伴生对象之后。

2.6 接口实现结构

实现接口时,应保持实现的成员与接口成员的顺序一致(如有必要,可以插入实现所用的私有方法)。

2.7 重载方法结构

类中的重载方法应始终放在一起。

3. 命名规则

Kotlin 中的包和类命名规则非常简单:

  • 包名始终使用小写,且不使用下划线(如 org.example.project)。通常不建议使用多词名称,但如果确实需要使用多个单词,可以将它们直接连接或使用驼峰命名法(如 org.example.myProject)。
  • 类和对象的名称使用大驼峰命名法:
open class DeclarationProcessor { /*...*/ }

object EmptyDeclarationProcessor : DeclarationProcessor() { /*...*/ }

3.1 函数命名

函数、属性和局部变量的名称以小写字母开头,使用驼峰命名法,且不使用下划线:

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

例外情况:用于创建类实例的工厂函数,可以与抽象返回类型同名:

interface Foo { /*...*/ }

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

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

3.2 测试方法命名

在测试中(仅在测试中),可以使用反引号包裹包含空格的方法名。请注意,此类方法名仅在 API 级别 30 及以上的 Android 运行时中受支持。测试代码中也允许在方法名中使用下划线。

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

    @Test fun ensureEverythingWorks_onAndroid() { /*...*/ }
}

3.3 属性命名

常量(标记为 const 的属性,或顶层、对象中的 val 属性且无自定义 get 函数、持有深度不可变数据的属性)的名称应使用全大写、下划线分隔的命名方式,遵循“大写下划线命名法”(screaming snake case)规范:

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 }),也可以使用大驼峰命名法,具体取决于使用场景。

3.4 后备属性命名

如果一个类有两个在概念上相同的属性,但其中一个属于公共 API,另一个是实现细节,则私有属性的名称应以下划线为前缀:

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

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

3.5 选择合适的名称

类名通常是名词或名词短语,用于说明该类“是什么”:例如 ListPersonReader

方法名通常是动词或动词短语,用于说明该方法“做什么”:例如 closereadPersons。方法名还应暗示该方法是会修改对象还是返回一个新对象。例如,sort 表示对集合进行原地排序,而 sorted 表示返回集合的排序副本。

名称应清晰表明实体的用途,因此最好避免在名称中使用无意义的词汇(如 ManagerWrapper)。

当声明名称中包含缩写词时,应遵循以下规则:

  • 对于两个字母的缩写词,两个字母都使用大写。例如:IOStream
  • 对于超过两个字母的缩写词,仅首字母大写。例如:XmlFormatterHttpInputStream

4. 格式规范

4.1 缩进

使用 4 个空格进行缩进,不使用制表符(Tab)。

对于花括号,左花括号放在构造开始行的末尾,右花括号单独成行,并与构造开始处水平对齐。

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

在 Kotlin 中,分号是可选的,因此换行具有重要意义。该语言的设计采用了 Java 风格的花括号格式,如果尝试使用其他格式风格,可能会遇到意外情况。

4.2 水平空白

  • 在二元运算符前后添加空格(如 a + b)。例外情况:“范围到”运算符(0..i)前后不添加空格。
  • 一元运算符前后不添加空格(如 a++)。
  • 在控制流关键字(ifwhenforwhile)与其对应的左括号之间添加空格。
  • 在主构造函数声明、方法声明或方法调用中,左括号前不添加空格。
class A(val x: Int)

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

fun bar() {
    foo(1)
}
  • ([ 之后,或 ]) 之前,绝不添加空格。
  • .?. 前后绝不添加空格:例如 foo.bar().filter { it > 2 }.joinToString()foo?.bar()。`
  • // 之后添加空格:例如 // 这是一条注释
  • 在指定类型参数的尖括号(<>)前后不添加空格:例如 class Map<K, V> { ... }
  • :: 前后不添加空格:例如 Foo::classString::length
  • 在标记可空类型的 ? 之前不添加空格:例如 String?

一般规则:避免任何形式的水平对齐。将标识符重命名为长度不同的名称时,不应影响声明或任何使用处的格式。

4.3 冒号

在以下场景中,冒号(:)前添加空格:

  • 用于分隔类型与其超类型时。
  • 委托给超类构造函数或同一类的其他构造函数时。
  • object 关键字之后时。

当冒号用于分隔声明与其类型时,冒号前不添加空格。

冒号后始终添加空格。

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 { /*...*/ }
}

4.4 类头

具有少量主构造函数参数的类可以写在一行中:

class Person(id: Int, name: String)

对于头较长的类,应进行格式化,使每个主构造函数参数单独成行并缩进。此外,右括号应单独成行。如果使用继承,超类构造函数调用或实现的接口列表应与右括号位于同一行:

class Person(
    id: Int,
    name: String,
    surname: String
) : Human(id, name) { /*...*/ }

对于实现多个接口的情况,超类构造函数调用应放在第一位,然后每个接口单独成行:

class Person(
    id: Int,
    name: String,
    surname: String
) : Human(id, name),
    KotlinMaker { /*...*/ }

对于超类型列表较长的类,在冒号后换行,并将所有超类型名称水平对齐:

class MyFavouriteVeryLongClassHolder :
    MyLongHolder<MyFavouriteVeryLongClass>(),
    SomeOtherInterface,
    AndAnotherOne {

    fun foo() { /*...*/ }
}

当类头较长时,为了清晰区分类头和类体,可以在类头后添加一个空行(如上例所示),或者将左花括号单独成行:

class MyFavouriteVeryLongClassHolder :
    MyLongHolder<MyFavouriteVeryLongClass>(),
    SomeOtherInterface,
    AndAnotherOne
{
    fun foo() { /*...*/ }
}

构造函数参数使用常规缩进(4 个空格)。这样可以确保主构造函数中声明的属性与类体中声明的属性缩进一致。

4.5 修饰符顺序

如果一个声明有多个修饰符,应始终按以下顺序排列:

public / protected / private / internal
expect / actual
final / open / abstract / sealed / const
external
override
lateinit
tailrec
vararg
suspend
inner
enum / annotation / fun // 作为 `fun interface` 中的修饰符
companion
inline / value
infix
operator
data

所有注解都应放在修饰符之前:

@Named("Foo")
private val foo: Foo

除非你正在开发库,否则应省略冗余的修饰符(例如 public)。

4.6 注解

注解应放在其附加的声明之前的单独行上,并且缩进相同:

@Target(AnnotationTarget.PROPERTY)
annotation class JsonExclude

无参数的注解可以放在同一行:

@JsonExclude @JvmField
var x: String

单个无参数的注解可以与对应的声明放在同一行:

@Test fun foo() { /*...*/ }

4.7 文件注解

文件注解(如果有文件注释)应放在文件注释之后、package 语句之前,并且与 package 之间用一个空行分隔(以强调它们作用于文件而非包)。

/** 许可证、版权信息等 */
@file:JvmName("FooBar")

package foo.bar

4.8 函数

如果函数签名无法放在一行中,使用以下语法:

fun longMethodName(
    argument: ArgumentType = defaultValue,
    argument2: AnotherArgumentType,
): ReturnType {
    // 函数体
}

函数参数使用常规缩进(4 个空格),这有助于确保与构造函数参数的一致性。

对于仅由单个表达式组成函数体的函数,优先使用表达式体。

fun foo(): Int {     // 不好的写法
    return 1
}

fun foo() = 1        // 好的写法

4.9 表达式体

如果函数的表达式体的第一行无法与声明放在同一行,将 = 放在第一行,并将表达式体缩进 4 个空格。

fun f(x: String, y: String, z: String) =
    veryLongFunctionCallWithManyWords(andLongParametersToo(), x, y, z)

4.10 属性

对于非常简单的只读属性,可以考虑单行格式:

val isEmpty: Boolean get() = size == 0

对于更复杂的属性,getset 关键字应始终放在单独的行上:

val foo: String
    get() { /*...*/ }

对于带有初始化器的属性,如果初始化器较长,在 = 后换行,并将初始化器缩进 4 个空格:

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

4.11 控制流语句

如果 ifwhen 语句的条件是多行的,语句体必须使用花括号包裹。条件的后续每行相对于语句开始处缩进 4 个空格。条件的右括号与左花括号一起放在单独的行上:

if (!component.isSyncing &&
    !hasAnyKotlinRuntimeInScope(module)
) {
    return createKotlinNotConfiguredPanel(module)
}

这样有助于对齐条件和语句体。

elsecatchfinally 关键字以及 do-while 循环的 while 关键字放在前一个花括号的同一行:

if (condition) {
    // 语句体
} else {
    // else 部分
}

try {
    // 语句体
} finally {
    // 清理操作
}

when 语句中,如果某个分支超过一行,可以考虑在其与相邻分支块之间添加一个空行:

private fun parsePropertyValue(propName: String, token: Token) {
    when (token) {
        is Token.ValueToken ->
            callback.visitValue(propName, token.value)

        Token.LBRACE -> { // ...
        }
    }
}

短分支与条件放在同一行,不使用花括号。

when (foo) {
    true -> bar() // 好的写法
    false -> { baz() } // 不好的写法
}

4.12 方法调用

对于较长的参数列表,在左括号后换行。参数缩进 4 个空格。将多个紧密相关的参数分组放在同一行。

drawSquare(
    x = 10, y = 10,
    width = 100, height = 100,
    fill = true
)

在分隔参数名和值的 = 前后添加空格。

4.13 链式调用换行

当链式调用需要换行时,将 . 字符或 ?. 运算符放在下一行,并缩进一次:

val anchor = owner
    ?.firstChild!!
    .siblings(forward = true)
    .dropWhile { it is PsiComment || it is PsiWhiteSpace }

链式调用中的第一个调用通常应在其前换行,但如果代码这样更合理,也可以省略。

4.14 lambda 表达式

在 lambda 表达式中,花括号前后以及分隔参数和体的箭头(->)前后都应添加空格。如果一个调用仅接受一个 lambda 作为参数,只要可能,就将其放在括号外传递。

list.filter { it > 10 }

如果为 lambda 指定标签,标签与左花括号之间不添加空格:

fun foo() {
    ints.forEach lit@{
        // ...
    }
}

在多行 lambda 中声明参数名时,将参数名放在第一行,后跟箭头并换行:

appendCommaSeparated(properties) { prop ->
    val propertyValue = prop.get(obj)  // ...
}

如果参数列表太长无法放在一行,将箭头放在单独的行上:

foo {
    context: Context,
    environment: Env
    ->
    context.configureEnv(environment)
}

4.15 尾随逗号

尾随逗号是指在一系列元素的最后一个元素之后的逗号符号:

class Person(
    val firstName: String,
    val lastName: String,
    val age: Int, // 尾随逗号
)

使用尾随逗号有以下几个好处:

  • 使版本控制的差异更清晰——所有关注点都集中在修改的值上。
  • 便于添加和重新排序元素——操作元素时无需添加或删除逗号。
  • 简化代码生成,例如对象初始化器。最后一个元素也可以带有逗号。

尾随逗号是完全可选的——即使不使用,代码也能正常运行。Kotlin 风格指南建议在声明处使用尾随逗号,调用处则由你自行决定。

要在 IntelliJ IDEA 格式化程序中启用尾随逗号,请进入 设置/偏好设置 | 编辑器 | 代码风格 | Kotlin,打开 其他(Other)选项卡,选中 使用尾随逗号(Use trailing comma)选项。

5. 文档注释

对于较长的文档注释,将开头的 /** 放在单独的行上,后续每行以星号(*)开头:

/**
 * 这是一个多行文档注释
 * 跨越多行。
 */

短注释可以放在一行中:

/** 这是一个短文档注释。 */

通常,避免使用 @param@return 标签。相反,应将参数和返回值的描述直接融入文档注释中,并在提及参数的地方添加链接。仅当需要冗长的描述且无法融入正文流程时,才使用 @param@return

// 避免这样做:

/**
 * 返回给定数字的绝对值。
 * @param number 要返回其绝对值的数字。
 * @return 绝对值。
 */
fun abs(number: Int): Int { /*...*/ }

// 应该这样做:

/**
 * 返回给定 [number] 的绝对值。
 */
fun abs(number: Int): Int { /*...*/ }

6. 避免冗余构造

一般来说,如果 Kotlin 中的某个语法构造是可选的,并且被 IDE 标记为冗余,就应在代码中省略它。不要为了“清晰”而在代码中保留不必要的语法元素。

6.1 Unit 返回类型

如果函数返回 Unit,应省略返回类型:

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

}

6.2 分号

尽可能省略分号。

6.3 字符串模板

将简单变量插入字符串模板时,不要使用花括号。仅对较长表达式使用花括号:

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

使用多美元符号字符串插值将美元符号($)视为字符串字面量:

val KClass<*>.jsonSchema : String
    get() = $$"""
        {
            "$schema": "<https://json-schema.org/draft/2020-12/schema>",
            "$id": "<https://example.com/product.schema.json>",
            "$dynamicAnchor": "meta",
            "title": "${simpleName ?: qualifiedName ?: "unknown"}",
            "type": "object"
        }
        """

7. 语言特性的惯用用法

7.1 不可变性

优先使用不可变数据而非可变数据。如果局部变量和属性在初始化后不被修改,应始终将其声明为 val 而非 var

对于不被修改的集合,应始终使用不可变集合接口(CollectionListSetMap)进行声明。使用工厂函数创建集合实例时,只要可能,就应使用返回不可变集合类型的函数:

// 不好的写法:对不会被修改的值使用可变集合类型
fun validateValue(actualValue: String, allowedValues: HashSet<String>) { ... }

// 好的写法:改用不可变集合类型
fun validateValue(actualValue: String, allowedValues: Set<String>) { ... }

// 不好的写法:arrayListOf() 返回 ArrayList<T>,这是一种可变集合类型
val allowedValues = arrayListOf("a", "b", "c")

// 好的写法:listOf() 返回 List<T>
val allowedValues = listOf("a", "b", "c")

7.2 默认参数值

优先为函数声明默认参数值,而非声明重载函数。

// 不好的写法
fun foo() = foo("a")
fun foo(a: String) { /*...*/ }

// 好的写法
fun foo(a: String = "a") { /*...*/ }

7.3 类型别名

如果某个函数式类型或带类型参数的类型在代码库中多次使用,优先为其定义类型别名:

typealias MouseClickHandler = (Any, MouseEvent) -> Unit
typealias PersonIndex = Map<String, Person>

如果使用私有或内部类型别名来避免命名冲突,优先使用 包和导入 中提到的 import ... as ... 语法。

7.4 Lambda 参数

对于简短且非嵌套的 lambda 表达式,建议使用 it 约定,而非显式声明参数。对于带参数的嵌套 lambda 表达式,始终显式声明参数。

7.5 Lambda 中的返回语句

避免在 lambda 表达式中使用多个带标签的返回语句。考虑重构 lambda 表达式,使其只有一个退出点。如果无法实现或不够清晰,可以将 lambda 表达式转换为匿名函数。

不要对 lambda 表达式中的最后一条语句使用带标签的返回。

7.6 命名参数

当方法接受多个相同基本类型的参数,或接受 Boolean 类型的参数时,应使用命名参数语法,除非所有参数的含义从上下文来看非常明确。

drawSquare(x = 10, y = 10, width = 100, height = 100, fill = true)

7.7 条件语句

优先使用 tryifwhen 的表达式形式。

return if (x) foo() else bar()
return when(x) {
    0 -> "zero"
    else -> "nonzero"
}

上述写法优于:

if (x)
    return foo()
else
    return bar()
when(x) {
    0 -> return "zero"
    else -> return "nonzero"
}

7.8 if 与 when 的选择

对于二元条件,优先使用 if 而非 when。例如,使用以下 if 语法:

if (x == null) ... else ...

而非以下 when 语法:

when (x) {
    null -> // ...
    else -> // ...
}

如果有三个或更多选项,优先使用 when

7.9 when 表达式中的守护条件

when 表达式或语句中使用 守护条件 组合多个布尔表达式时,应使用括号:

when (status) {
    is Status.Ok if (status.info.isEmpty() || status.info.id == null) -> "no information"
}

而非:

when (status) {
    is Status.Ok if status.info.isEmpty() || status.info.id == null -> "no information"
}

7.10 条件中的可空 Boolean 值

如果需要在条件语句中使用可空 Boolean 值,应使用 if (value == true)if (value == false) 进行检查。

7.11 循环

优先使用高阶函数(filtermap 等)而非循环。例外情况forEach(优先使用常规 for 循环,除非 forEach 的接收者是可空的,或 forEach 是较长调用链的一部分)。

在使用多个高阶函数的复杂表达式和循环之间做选择时,应了解每种情况下所执行操作的成本,并考虑性能因素。

7.12 范围循环

使用 ..

for (i in 0..n - 1) { /*...*/ }  // 不好的写法
for (i in 0..<n) { /*...*/ }  // 好的写法

7.13 字符串

优先使用字符串模板而非字符串拼接。

优先使用多行字符串而非在常规字符串字面量中嵌入 \n 转义序列。

要保持多行字符串的缩进,如果生成的字符串不需要任何内部缩进,使用 trimIndent;如果需要内部缩进,使用 trimMargin

println("""
    Not
    trimmed
    text
""")

println("""
    Trimmed
    text
""".trimIndent())

println()

val a = """Trimmed to margin text:
            |if(a > 1) {
            |    return a
            |}""".trimMargin()
println(a)

([在 Playground 中打开 →])

目标:JVM 运行于 v.2.2.21

了解 Java 与 Kotlin 多行字符串的区别

7.14 函数与属性的选择

在某些场景下,无参数函数可能与只读属性可互换。尽管语义相似,但在选择使用哪一种时,存在一些风格约定。

当底层算法满足以下条件时,优先使用属性而非函数:

  • 不抛出异常。
  • 计算成本低(或在第一次运行时缓存)。
  • 如果对象状态未改变,多次调用返回相同结果。

7.15 扩展函数

大量使用扩展函数。每当有一个主要操作某个对象的函数时,考虑将其设为接受该对象作为接收者的扩展函数。为了最小化 API 冗余,应尽可能限制扩展函数的可见性。必要时,使用局部扩展函数、成员扩展函数或具有私有可见性的顶层扩展函数。

7.16 中缀函数

仅当函数作用于两个角色相似的对象时,才将其声明为 infix。好的例子:andtozip。不好的例子:add

如果方法会修改接收者对象,不要将其声明为 infix

7.17 工厂函数

为类声明工厂函数时,避免使用与类名相同的名称。优先使用含义明确的独特名称,以清晰表明该工厂函数的行为有何特殊之处。只有当确实没有特殊语义时,才可以使用与类名相同的名称。

class Point(val x: Double, val y: Double) {
    companion object {
        fun fromPolar(angle: Double, radius: Double) = Point(...)
    }
}

如果一个对象有多个重载构造函数,且这些构造函数不调用不同的超类构造函数,也无法简化为包含默认参数的单个构造函数,优先将重载构造函数替换为工厂函数。

7.18 平台类型

返回平台类型表达式的公共函数/方法必须显式声明其 Kotlin 类型:

fun apiCall(): String = MyJavaApi.getProperty("name")

任何使用平台类型表达式初始化的属性(包级或类级)必须显式声明其 Kotlin 类型:

class Person {
    val name: String = MyJavaApi.getProperty("name")
}

使用平台类型表达式初始化的局部变量可以声明也可以不声明类型:

fun main() {
    val name = MyJavaApi.getProperty("name")
    println(name)
}

7.19 作用域函数 apply/with/run/also/let

Kotlin 提供了一组用于在给定对象的上下文中执行代码块的函数:letrunwithapplyalso。有关如何为具体场景选择合适作用域函数的指导,请参阅 作用域函数

8. 库的编码规范

编写库时,建议遵循额外的一组规则以确保 API 稳定性:

  • 始终显式指定成员可见性(以避免意外将声明暴露为公共 API)。
  • 始终显式指定函数返回类型和属性类型(以避免在实现更改时意外更改返回类型)。
  • 为所有公共成员提供 KDoc 注释,除非是不需要任何新文档的重写方法(以支持为库生成文档)。

有关编写库 API 时应考虑的最佳实践和思路的更多信息,请参阅 库作者指南编辑页面

有关编写库 API 时应考虑的最佳实践和思路的更多信息,请参阅 库作者指南