跳转至

Kotlin 编码风格

此文件使用 Kotlin 特定内容扩展 common/coding-style.md。

格式

  • 使用 ktlint 或 Detekt 强制风格
  • 官方 Kotlin 代码风格(gradle.properties 中 kotlin.code.style=official)

不可变性

  • 优先使用 val 而不是 var — 默认使用 val,仅在需要修改时使用 var
  • 值类型使用 data class;公共 API 中使用不可变集合(List、Map、Set)
  • 状态更新使用写时复制:state.copy(field = newValue)

命名

遵循 Kotlin 惯例: - camelCase — 函数和属性 - PascalCase — 类、接口、对象、类型别名 - SCREAMING_SNAKE_CASE — 常量(const val 或 @JvmStatic) - 接口前缀按行为命名,而不是 I:使用 Clickable,而不是 IClickable

Null 安全性

  • 不使用 !! — 优先使用 ?.、?:、requireNotNull() 或 checkNotNull()
  • 对于作用域内的 null 安全操作使用 ?.let {}
  • 从可能合理地没有结果的函数返回可空类型
// BAD
val name = user!!.name

// GOOD
val name = user?.name ?: "Unknown"
val name = requireNotNull(user) { "User must be set before accessing name" }.name

密封类型

对封闭的状态层次结构建模时使用密封类/接口:

sealed interface UiState<out T> {
    data object Loading : UiState<Nothing>
    data class Success<T>(val data: T) : UiState<T>
    data class Error(val message: String) : UiState<Nothing>
}

对密封类型始终使用穷举的 when — 不使用 else 分支。

扩展函数

对实用操作使用扩展函数,但要便于发现: - 文件名与接收者类型相关(StringExt.kt、FlowExt.kt) - 限定作用域 — 不要为 Any 或过于通用的类型添加扩展

作用域函数

使用合适的作用域函数: - let — null 检查 + 转换:user?.let { greet(it) } - run — 使用接收者计算结果:service.run { fetch(config) } - apply — 配置对象:builder.apply { timeout = 30 } - also — 副作用:result.also { log(it) } - 避免作用域函数深度嵌套(最多 2 层)

错误处理

  • 使用 Result<T> 或自定义密封类型
  • 对可抛出代码的包装使用 runCatching {}
  • 绝对不要捕获 CancellationException — 始终重新抛出
  • 不要在控制流中使用 try-catch
// BAD — 控制フローに例外を使用
val user = try { repository.getUser(id) } catch (e: NotFoundException) { null }

// GOOD — nullable 戻り値
val user: User? = repository.findUser(id)

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 ev/ECC