如何在 Kotlin 中为数据 类 指定类型类
How to specify a typeclass for data classes in Kotlin
在 scala
中,支持 case class
的父 class 是 product
:因此我们可以将其用于跨 case classe
的多态性。 kotlin
中的 data class
es 如何实现类似的目标?
对于下面的 yaml
解析器,我需要替换 dataclass
来代表所有 data classes
.
的合理父 class
inline fun <reified T: dataclass> loadFromFileDC(path: Path): T = loadFromFile(path, T::class)
fun <T: dataclass> loadFromFile(path: Path, cls: KClass<T>) = {
val mapper = ObjectMapper(YAMLFactory()) // Enable YAML parsing
mapper.registerModule(KotlinModule()) // Enable Kotlin support
Files.newBufferedReader(path).use {
mapper.readValue(it, cls.java)
}
}
如果我没理解错的话,我认为在 Kotlin 中是不可能的。数据 classes 只是普通的 classes。因此,您可以从任何 open/abstract class、接口或密封 class 继承它。同时,也没有办法继承dataclass,比如强制所有children都是dataclass。并且没有特定于数据 class 的继承,因为正如我提到的,数据 class 只是一个普通的 class,具有预定义和预生成的一堆方法。
我认为这也值得思考:你真的需要在编译时将每个传递的 class 识别为数据 class,为什么你真的需要它?
例如,如果您想应用任何类型的多态性,那么您只能使用 equals
/hashCode
/toString
,因为 componenN
和copy
函数刚刚生成,没有可以覆盖的基本函数。
因为每个 class 都可以 实现这 3 个方法。您所能做的就是强制执行它们。例如:
interface DataClass {
override fun equals(other: Any?): Boolean
override fun hashCode(): Int
override fun toString(): String
}
data class Impl(val t: Int) : DataClass
在那种情况下,很可能会强制执行数据 class,或者强制提供所有 3 个所需的方法。但这是 hack 而不是实际解决方案,您将无法将其应用于 3rd-party-classes,因为您将无法使用此界面标记它们。
总而言之:我建议您考虑一下您是否真的需要知道,您的示例 data class
中的 clz
是什么,或者它可以是任何东西。如果是,那么您可以考虑使用反射。
请看这个:
在 scala
中,支持 case class
的父 class 是 product
:因此我们可以将其用于跨 case classe
的多态性。 kotlin
中的 data class
es 如何实现类似的目标?
对于下面的 yaml
解析器,我需要替换 dataclass
来代表所有 data classes
.
inline fun <reified T: dataclass> loadFromFileDC(path: Path): T = loadFromFile(path, T::class)
fun <T: dataclass> loadFromFile(path: Path, cls: KClass<T>) = {
val mapper = ObjectMapper(YAMLFactory()) // Enable YAML parsing
mapper.registerModule(KotlinModule()) // Enable Kotlin support
Files.newBufferedReader(path).use {
mapper.readValue(it, cls.java)
}
}
如果我没理解错的话,我认为在 Kotlin 中是不可能的。数据 classes 只是普通的 classes。因此,您可以从任何 open/abstract class、接口或密封 class 继承它。同时,也没有办法继承dataclass,比如强制所有children都是dataclass。并且没有特定于数据 class 的继承,因为正如我提到的,数据 class 只是一个普通的 class,具有预定义和预生成的一堆方法。
我认为这也值得思考:你真的需要在编译时将每个传递的 class 识别为数据 class,为什么你真的需要它?
例如,如果您想应用任何类型的多态性,那么您只能使用 equals
/hashCode
/toString
,因为 componenN
和copy
函数刚刚生成,没有可以覆盖的基本函数。
因为每个 class 都可以 实现这 3 个方法。您所能做的就是强制执行它们。例如:
interface DataClass {
override fun equals(other: Any?): Boolean
override fun hashCode(): Int
override fun toString(): String
}
data class Impl(val t: Int) : DataClass
在那种情况下,很可能会强制执行数据 class,或者强制提供所有 3 个所需的方法。但这是 hack 而不是实际解决方案,您将无法将其应用于 3rd-party-classes,因为您将无法使用此界面标记它们。
总而言之:我建议您考虑一下您是否真的需要知道,您的示例 data class
中的 clz
是什么,或者它可以是任何东西。如果是,那么您可以考虑使用反射。
请看这个: