在 Kotlin 中模拟属性的包隐私

Simulate package-privacy on properties in Kotlin

所以,我有一个名为 Level 的枚举。该枚举实际上只是其他一些级别的包装器。现在我需要访问位于同一包中的另一个名为 Log 的不同 class 中的包装值(当前为 protected 属性)。显然,我不想通过 internalpublic 来完全公开 属性,但我需要在我的日志 class.[=27= 中访问该包装值] 我该怎么做?

由于 Kotlin 没有提供任何类似于包私有可见性的东西,所以我尝试的一切都失败了。我已经知道可以将两个 classes 放在一个文件中,但这只允许我获得对 classes 本身的独占访问权,而不是它们的属性。而且因为我需要同时拥有 class 和 public 这两个都无济于事。因此,如果有人知道解决方法,我会非常高兴听到它,因为即使我真的很喜欢 Kotlin,这也可能是我放弃这门语言的原因。

我提到的两个 class 看起来如下:
Level.kt

enum class Level(protected val level: java.util.logging.Level) {
    /** Useful for stuff */
    OFF(CustomLevel("OFF", Int.MAX_VALUE)),
    ASSERT(CustomLevel("ASSERT", 1200)),
    FATAL(CustomLevel("FATAL", 1100)),
    ERROR(CustomLevel("ERROR", 1000)),
    WARN(CustomLevel("WARN", 900)),
    INFO(CustomLevel("INFO", 800)),
    DEBUG(CustomLevel("DEBUG", 700)),
    ALL(CustomLevel("ALL", Int.MIN_VALUE));

    private class CustomLevel(name: String, value: Int) : java.util.logging.Level(name, value)
}

Log.kt

object Log {
    private val DEFAULT_CONSOLE_VERBOSITY = Level.ERROR
    private val DEFAULT_FILE_VERBOSITY = Level.ALL

    @JvmStatic
    var consoleVerbosity: Level
        get() = Level.findLevel(consoleHandler.level)
        set(value) {
            consoleHandler.level = value.level // The property I need to access
        }
    @JvmStatic
    var fileVerbosity: Level
        get() = Level.findLevel(fileHandler.level)
        set(value) {
            fileHandler.level = value.level // The property I need to access
        }

    private val consoleHandler = ConsoleHandler()
    init {
        consoleHandler.formatter = SimpleFormatter()
        consoleHandler.level = DEFAULT_CONSOLE_VERBOSITY.level
    }
    private val fileHandler = FileHandler()
    init {
        fileHandler.formatter = SimpleFormatter()
        fileHandler.level = DEFAULT_FILE_VERBOSITY.level
    }
}

我是运行 Kotlin最新稳定版(1.4.31)

你只需要像这样使用扩展函数:

fun Level.toLevel() = this.level

这允许您访问其他 类 的受保护属性。

您无法从另一个 class 访问私有 class,但您可以从打包在文件中的 class 访问 class。因此,解决方法是在 public class 中取笑以访问同一文件中的私有 class。

但重点是您不能在 Kotlin 中的枚举 class 中写入 class。

我仍然不知道你是如何在 IDE 中写下这段代码的,因为它会显示错误。

作为解决方法,您可以在 Level class:

的范围内为 Log class 定义一个扩展 function/property
enum class Level(private val level: java.util.logging.Level) {
    //...
    
    //Option 1
    companion object {
        fun Log.getLevelOf(level: Level) = level.level
    }
 
    //Option 2
    val Log._level get() = level
}

您还可以在 Log class 的范围内为 Level class 定义扩展名 属性 以获得更自然的用法:

object Log {
   //...

    private val Level.level : java.util.logging.Level
        get() = consoleHandler.level = Level.run { getLevelOf(this@level) } // For Option 1
        get() = with(this) { _level } // For Option 2
}

这种方法的缺点是这些 class 之间的耦合很难。