ZetCode

Kotlin 文件关键字

最后修改于 2025 年 4 月 19 日

Kotlin 的 file 关键字用于指定顶级声明的可见性修饰符。它控制对同一文件内声明的访问。本教程通过实际例子探讨了文件级可见性。

基本定义

Kotlin 中的 file 可见性修饰符使声明仅在同一源文件中可见。对于顶级声明,它比 internal 更严格,但比 private 宽松。

基本的文件私有可见性

file 关键字将可见性限制为当前文件。这对于不应在外部公开的辅助函数或类很有用。

Utils.kt
package com.zetcode.utils

file fun calculateSquare(x: Int): Int {
    return x * x
}

fun publicCalculateCube(x: Int): Int {
    return x * x * x
}

fun main() {
    println(calculateSquare(5)) // Accessible: 25
    println(publicCalculateCube(3)) // Accessible: 27
}

在这里,calculateSquare 是文件私有的,只能在 Utils.kt 中使用。publicCalculateCube 可从其他文件访问。两者都可以在同一文件中的 main 函数中访问。

文件私有类

类也可以使用 file 修饰符标记为文件私有。这对于不应泄露到文件外部的实现细节很有用。

Database.kt
package com.zetcode.db

file class DatabaseConnection(private val url: String) {
    fun connect() = println("Connected to $url")
}

fun createConnection(): DatabaseConnection {
    return DatabaseConnection("jdbc:mysql:///mydb")
}

fun main() {
    val conn = createConnection()
    conn.connect() // Works within same file
}

DatabaseConnection 类仅在 Database.kt 中可见。createConnection 函数可以返回它,因为它们在同一个文件中。外部文件无法直接创建 DatabaseConnection 实例。

文件私有属性

顶级属性可以是文件私有的,以便在文件内共享状态,同时将其对其他文件隐藏。这对于模块级常量很有用。

Config.kt
package com.zetcode.config

file const val MAX_RETRIES = 3
const val TIMEOUT = 5000L

fun shouldRetry(attempt: Int): Boolean {
    return attempt < MAX_RETRIES
}

fun main() {
    println(shouldRetry(2)) // true
    println("Timeout: $TIMEOUT") // 5000
}

MAX_RETRIES 是文件私有的,而 TIMEOUT 是 public 的。两者都可以在 Config.kt 中访问,但只有 TIMEOUT 可以从其他文件访问。这控制了哪些实现细节被公开。

文件私有扩展函数

扩展函数可以是文件私有的,以限制其范围。这可以防止用仅在本地需要的扩展污染全局命名空间。

StringUtils.kt
package com.zetcode.utils

file fun String.encrypt(): String {
    return this.reversed()
}

fun String.publicEncrypt(): String {
    return encrypt() // Can call file-private function
}

fun main() {
    val secret = "password".encrypt() // Works
    println(secret) // Output: drowssap
}

encrypt 扩展仅在 StringUtils.kt 中可用。publicEncrypt 可以在内部使用它。这种模式可以防止辅助扩展对其他文件可见,同时仍然可以在内部重复使用。

文件私有接口

接口可以是文件私有的,以将其实现限制为当前文件。这对于组件之间的内部约定很有用。

Logger.kt
package com.zetcode.logging

file interface Logger {
    fun log(message: String)
}

class ConsoleLogger : Logger {
    override fun log(message: String) {
        println("[LOG] $message")
    }
}

fun createLogger(): Logger {
    return ConsoleLogger()
}

fun main() {
    val logger = createLogger()
    logger.log("Test message") // [LOG] Test message
}

Logger 接口仅在 Logger.kt 中可见。外部文件可以使用 createLogger 但不能直接实现 Logger。这强制执行创建记录器的受控方式。

文件私有伴生对象

伴生对象成员可以是文件私有的,以便在类方法之间共享实现细节,同时将其对其他文件隐藏。

IdGenerator.kt
package com.zetcode.utils

class IdGenerator {
    companion object {
        file var counter = 0
        file fun nextId() = ++counter
    }
    
    fun generate(): Int {
        return nextId() // Can access file-private members
    }
}

fun main() {
    val gen = IdGenerator()
    println(gen.generate()) // 1
    println(gen.generate()) // 2
}

counternextId 是文件私有的,但可被所有 IdGenerator 方法访问。这维护了状态,同时防止外部修改。每次调用 generate 都会增加计数器。

文件私有和内部可见性

当比较 fileinternal 可见性时,file 更严格。internal 使声明对整个模块可见。

Visibility.kt
package com.zetcode.visibility

file val filePrivate = "File private"
internal val moduleVisible = "Module visible"

fun printValues() {
    println(filePrivate) // Accessible
    println(moduleVisible) // Accessible
}

fun main() {
    printValues()
}

filePrivate 仅在 Visibility.kt 中可见,而 moduleVisible 可以从同一模块中的任何文件访问。两者都可以在声明它们的文件中访问。

文件私有声明的最佳实践

来源

Kotlin 可见性修饰符文档

本教程深入探讨了 Kotlin 的 file 可见性修饰符。我们探讨了各种用例,包括函数、类、属性和接口。正确使用文件私有可见性有助于创建干净、模块化的代码,并对实现细节进行良好控制的访问。

作者

我叫 Jan Bodnar,是一位充满激情的程序员,拥有多年的编程经验。自 2007 年以来,我一直在撰写编程文章。到目前为止,我写了 1400 多篇文章和 8 本电子书。我有超过八年的编程教学经验。

列出 所有 Kotlin 教程