在 Kotlin 中模拟属性的包隐私
Simulate package-privacy on properties in Kotlin
所以,我有一个名为 Level
的枚举。该枚举实际上只是其他一些级别的包装器。现在我需要访问位于同一包中的另一个名为 Log
的不同 class 中的包装值(当前为 protected
属性)。显然,我不想通过 internal
或 public
来完全公开 属性,但我需要在我的日志 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 之间的耦合很难。
所以,我有一个名为 Level
的枚举。该枚举实际上只是其他一些级别的包装器。现在我需要访问位于同一包中的另一个名为 Log
的不同 class 中的包装值(当前为 protected
属性)。显然,我不想通过 internal
或 public
来完全公开 属性,但我需要在我的日志 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 之间的耦合很难。